亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android如何使用自定義View中Spannable

發布時間:2020-07-22 10:40:31 來源:億速云 閱讀:207 作者:小豬 欄目:移動開發

這篇文章主要為大家展示了Android如何使用自定義View中Spannable,內容簡而易懂,希望大家可以學習一下,學習完之后肯定會有收獲的,下面讓小編帶大家一起來看看吧。

我們都知道 Android 中使用 Spannable 可以實現 TextView 富文本的顯示,但是在自定義控件中如何使用 Spannable 繪制不同樣式的文字呢?

Android如何使用自定義View中Spannable

例如這種效果,標題中的 分數字61 是粗體, 是常規字體,并且相對于 61 更小些。
第一反應可能是使用 SpannableString.setSpan() 設置 RelativeSizeSpan, 然后在 onDraw() 中進行繪制,事實是這樣實現是沒有效果的,因為 onDraw() 中只能獲取到 SpannableString 中的內容,拿不到 Span.

那如何在自定義View 中使用 Spannable 呢? 答案就是系統提供的 Layout 類,

/**
 * A base class that manages text layout in visual elements on
 * the screen.
 * <p>For text that will be edited, use a {@link DynamicLayout},
 * which will be updated as the text changes.
 * For text that will not change, use a {@link StaticLayout}.
 */
public abstract class Layout {
 
}

Android如何使用自定義View中Spannable

Android如何使用自定義View中Spannable

可以看到 Layout 是一個抽象類,有三個子類,可以實現一些自動換行的顯示效果。

  • BoringLayout
  • DynamicLayout
  • StaticLayout

實現代碼

1. 定義自定義屬性

<&#63;xml version="1.0" encoding="utf-8"&#63;>
<resources>
 <declare-styleable name="ArcProgressView">
  <attr name="arcBackgroundColor" format="color" />
  <attr name="arcProgressColor" format="color" />
  <attr name="arcSubTitleColor" format="color" />
  <attr name="arcStrokeWidth" format="dimension" />
  <attr name="arcTitleTextSize" format="dimension" />
  <attr name="arcSubTitleTextSize" format="dimension" />
  <attr name="arcProgress" format="float" />
  <attr name="arcTitleNumber" format="integer" />
 </declare-styleable>
</resources>

2. 繼承 View, 在 onDraw() 中繪制

public class ArcProgressView extends View {
 private int arcBackgroundColor; // 圓弧背景顏色
 private int arcProgressColor;  // 圓弧進度顏色
 private int arcSubTitleColor;  // 副標題顏色
 private float arcStrokeWidth;  // 圓弧線的厚度
 private float arcTitleTextSize; // 標題文字大小
 private float arcSubTitleTextSize; // 副標題文字大小
 private float arcProgress; // 進度
 private int arcTitleNumber; // 值
 private Paint paint;
 private float centerX;
 private float centerY;
 private float radius; // 半徑
 private RectF rectF;
 private int startAngle = 135;
 private int sweepAngle = 270;
 private String subTitle = "1月份";
 private SpannableString spannableString;
 private TextPaint textPaint;
 private RelativeSizeSpan relativeSizeSpan;
 private DynamicLayout dynamicLayout;
 private String text = "11分";
 private StyleSpan styleSpan;
 private float curProgress; // 當前進度
 private int curNumber;
 public ArcProgressView(Context context) {
  this(context, null);
 }
 public ArcProgressView(Context context, @Nullable AttributeSet attrs) {
  this(context, attrs, 0);
 }
 public ArcProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  readAttrs(context, attrs);
  init(context);
 }
 private void readAttrs(Context context, AttributeSet attributeSet) {
  TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.ArcProgressView);
  arcBackgroundColor = typedArray.getColor(R.styleable.ArcProgressView_arcBackgroundColor, 0x1c979797);
  arcProgressColor = typedArray.getColor(R.styleable.ArcProgressView_arcProgressColor, 0xff3372FF);
  arcSubTitleColor = typedArray.getColor(R.styleable.ArcProgressView_arcSubTitleColor, 0x66000000);
  arcStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.ArcProgressView_arcStrokeWidth, dp2px(5));
  arcTitleTextSize = typedArray.getDimensionPixelSize(R.styleable.ArcProgressView_arcTitleTextSize, dp2px(30));
  arcSubTitleTextSize = typedArray.getDimensionPixelSize(R.styleable.ArcProgressView_arcSubTitleTextSize, dp2px(14));
  arcProgress = typedArray.getFloat(R.styleable.ArcProgressView_arcProgress, 1.0f);
  arcTitleNumber = typedArray.getInt(R.styleable.ArcProgressView_arcTitleNumber, 100);
  typedArray.recycle();
 }
 private void init(Context context) {
  paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  paint.setStrokeCap(Paint.Cap.ROUND);
  relativeSizeSpan = new RelativeSizeSpan(0.6f);
  styleSpan = new StyleSpan(android.graphics.Typeface.BOLD);
  textPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
  textPaint.setColor(arcProgressColor);
//  textPaint.setTextAlign(Paint.Align.CENTER); // 設置該屬性導致文字間有間隔
  textPaint.setTextSize(sp2px(22));
 }
 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  centerX = w / 2f;
  centerY = h / 2f;
  radius = (Math.min(w, h) - arcStrokeWidth) / 2f;
  rectF = new RectF(-radius, -radius, radius, radius);
 }
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  int width = getMeasuredSize(widthMeasureSpec, dp2px(100));
  int height = getMeasuredSize(heightMeasureSpec, dp2px(100));
  setMeasuredDimension(width, height);
 }
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  // 繪制圓弧和進度
  drawArc(canvas);
  // 繪制文字 title
  drawTitleText(canvas);
  // 繪制文字副標題
  drawSubTitle(canvas);
 }
 @Override
 protected void onAttachedToWindow() {
  super.onAttachedToWindow();
  startAnimation();
 }
 private void startAnimation() {
  ValueAnimator progressAnimator = ValueAnimator.ofFloat(0f, arcProgress);
  ValueAnimator numberAnimator = ValueAnimator.ofInt(0, arcTitleNumber);
  progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    curProgress = (float) animation.getAnimatedValue();
    invalidate();
   }
  });
  numberAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    curNumber = (int) animation.getAnimatedValue();
    text = curNumber + "分";
   }
  });
  AnimatorSet animatorSet = new AnimatorSet();
  animatorSet.playTogether(progressAnimator, numberAnimator);
  animatorSet.setDuration(700);
  animatorSet.setInterpolator(new LinearInterpolator());
  animatorSet.start();
 }
 private void drawSubTitle(Canvas canvas) {
  canvas.save();
  canvas.translate(centerX, centerY);
  paint.setTextSize(arcSubTitleTextSize);
  paint.setTextAlign(Paint.Align.CENTER);
  paint.setColor(arcSubTitleColor);
  paint.setStyle(Paint.Style.FILL);
  paint.setStrokeWidth(0);
  canvas.drawText(subTitle, 0, 60, paint);
  canvas.restore();
 }
 private void drawArc(Canvas canvas) {
  canvas.save();
  canvas.translate(centerX, centerY);
  paint.setColor(arcBackgroundColor);
  paint.setStrokeWidth(arcStrokeWidth);
  paint.setStyle(Paint.Style.STROKE);
  canvas.drawArc(rectF, startAngle, sweepAngle, false, paint);
  paint.setColor(arcProgressColor);
  canvas.drawArc(rectF, startAngle, sweepAngle * curProgress, false, paint);
  canvas.restore();
 }
 private void drawTitleText(Canvas canvas) {
  canvas.save();
  textPaint.setTextSize(arcTitleTextSize);
  float textWidth = textPaint.measureText(text); // 文字寬度
  float textHeight = -textPaint.ascent() + textPaint.descent(); // 文字高度
  // 由于 StaticLayout 繪制文字時,默認畫在Canvas的(0,0)點位置,所以居中繪制居中位置,需要將畫布 translate到中間位置。
  canvas.translate(centerX - textWidth * 2 / 5f, centerY - textHeight * 2 / 3f);
  spannableString = SpannableString.valueOf(text);
  spannableString.setSpan(styleSpan, 0, text.length() - 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
  spannableString.setSpan(relativeSizeSpan, text.length() - 1, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  dynamicLayout = new DynamicLayout(spannableString, textPaint, getWidth(), Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
  dynamicLayout.draw(canvas);
  canvas.restore();
 }
 /**
  * 對外提供方法,設置進度
  *
  * @param percent
  */
 public void setArcProgress(float percent) {
  this.curProgress = percent;
  invalidate();
 }
 private int getMeasuredSize(int measureSpec, int defvalue) {
  int mode = MeasureSpec.getMode(measureSpec);
  int size = MeasureSpec.getSize(measureSpec);
  if (mode == MeasureSpec.EXACTLY) {
   return size;
  }
  return Math.min(size, defvalue);
 }
 private int dp2px(int dp) {
  return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
 }
 private int sp2px(int sp) {
  return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
 }
}

3. 在布局中引用

<com.xing.bottomsheetsample.ArcProgressView
  android:layout_width="match_parent"
  android:layout_height="100dp"
  android:layout_marginTop="20dp"
  app:arcProgress="0.6"
  app:arcSubTitleTextSize="14sp"
  app:arcTitleNumber="61"
  app:arcTitleTextSize="28sp" />

以上就是關于Android如何使用自定義View中Spannable的內容,如果你們有學習到知識或者技能,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

柳林县| 桐乡市| 定州市| 衡阳县| 呼图壁县| 襄樊市| 互助| 四川省| 池州市| 台东县| 崇义县| 台北县| 榆社县| 雅江县| 黄大仙区| 托克托县| 信丰县| 获嘉县| 深圳市| 崇左市| 贡嘎县| 丹棱县| 敦煌市| 康乐县| 咸丰县| 抚远县| 定兴县| 万全县| 贵州省| 沁阳市| 奉贤区| 岚皋县| 沅陵县| 黑龙江省| 阿瓦提县| 孟州市| 布尔津县| 铜鼓县| 钦州市| 甘德县| 南靖县|