欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android 自定義 View 中使用 Spannable的實(shí)例詳解

 更新時(shí)間:2020年05月25日 14:31:57   作者:星火燎原2016  
這篇文章主要介紹了Android 自定義 View 中使用 Spannable的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

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

例如這種效果,標(biāo)題中的 分?jǐn)?shù)字61 是粗體, 是常規(guī)字體,并且相對(duì)于 61 更小些。
第一反應(yīng)可能是使用 SpannableString.setSpan() 設(shè)置 RelativeSizeSpan, 然后在 onDraw() 中進(jìn)行繪制,事實(shí)是這樣實(shí)現(xiàn)是沒(méi)有效果的,因?yàn)?onDraw() 中只能獲取到 SpannableString 中的內(nèi)容,拿不到 Span.

那如何在自定義View 中使用 Spannable 呢? 答案就是系統(tǒng)提供的 Layout 類(lèi),

/**
 * 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 {
 
}

可以看到 Layout 是一個(gè)抽象類(lèi),有三個(gè)子類(lèi),可以實(shí)現(xiàn)一些自動(dòng)換行的顯示效果。

  • BoringLayout
  • DynamicLayout
  • StaticLayout

實(shí)現(xiàn)代碼

1. 定義自定義屬性

<?xml version="1.0" encoding="utf-8"?>
<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;  // 圓弧進(jìn)度顏色
 private int arcSubTitleColor;  // 副標(biāo)題顏色
 private float arcStrokeWidth;  // 圓弧線的厚度
 private float arcTitleTextSize; // 標(biāo)題文字大小
 private float arcSubTitleTextSize; // 副標(biāo)題文字大小
 private float arcProgress; // 進(jìn)度
 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; // 當(dāng)前進(jìn)度
 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); // 設(shè)置該屬性導(dǎo)致文字間有間隔
  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);
  // 繪制圓弧和進(jìn)度
  drawArc(canvas);
  // 繪制文字 title
  drawTitleText(canvas);
  // 繪制文字副標(biāo)題
  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 繪制文字時(shí),默認(rèn)畫(huà)在Canvas的(0,0)點(diǎn)位置,所以居中繪制居中位置,需要將畫(huà)布 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();
 }
 /**
  * 對(duì)外提供方法,設(shè)置進(jìn)度
  *
  * @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" />

總結(jié)

到此這篇關(guān)于Android 自定義 View 中使用 Spannable的文章就介紹到這了,更多相關(guān)Android 使用 Spannable內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android利用Xfermode剪裁圓角

    Android利用Xfermode剪裁圓角

    這篇文章主要為大家詳細(xì)介紹了Android利用Xfermode剪裁圓角,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Android 實(shí)現(xiàn)不依賴焦點(diǎn)和選中的TextView跑馬燈

    Android 實(shí)現(xiàn)不依賴焦點(diǎn)和選中的TextView跑馬燈

    本文主要介紹Android 跑馬燈的實(shí)現(xiàn),這里提供實(shí)現(xiàn)詳細(xì)實(shí)現(xiàn)代碼供大家參考,有需要的小伙伴可以看下
    2016-07-07
  • Android 4.0 設(shè)置全屏修改的解決方法

    Android 4.0 設(shè)置全屏修改的解決方法

    本篇文章是對(duì)Android 4.0 中設(shè)置全屏修改的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • 使用runtime 實(shí)現(xiàn)weex 跳轉(zhuǎn)原生頁(yè)面

    使用runtime 實(shí)現(xiàn)weex 跳轉(zhuǎn)原生頁(yè)面

    這篇文章主要介紹了使用runtime 實(shí)現(xiàn)weex 跳轉(zhuǎn)原生頁(yè)面的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • 如何將Android?Studio卸載干凈

    如何將Android?Studio卸載干凈

    這篇文章主要介紹了如何將Android?Studio卸載干凈,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • Android滑動(dòng)沖突的完美解決

    Android滑動(dòng)沖突的完美解決

    這篇文章主要為大家詳細(xì)介紹了Android滑動(dòng)沖突的完美解決方案,針對(duì)三種滑動(dòng)沖突場(chǎng)景進(jìn)行解決,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • 如何通過(guò)Battery Historian分析Android APP耗電情況

    如何通過(guò)Battery Historian分析Android APP耗電情況

    Android 從兩個(gè)層面統(tǒng)計(jì)電量的消耗,分別為軟件排行榜及硬件排行榜。它們各有自己的耗電榜單,軟件排行榜為機(jī)器中每個(gè) App 的耗電榜單,硬件排行榜則為各個(gè)硬件的耗電榜單。這兩個(gè)排行榜的統(tǒng)計(jì)是互為獨(dú)立,互不干擾的
    2021-06-06
  • Android沉浸式狀態(tài)欄微技巧(帶你真正理解沉浸式模式)

    Android沉浸式狀態(tài)欄微技巧(帶你真正理解沉浸式模式)

    因?yàn)锳ndroid官方從來(lái)沒(méi)有給出過(guò)沉浸式狀態(tài)欄這樣的命名,只有沉浸式模式(Immersive Mode)這種說(shuō)法.下面通過(guò)本文給大家介紹Android沉浸式狀態(tài)欄微技巧,需要的朋友參考下
    2016-12-12
  • Android在項(xiàng)目中接入騰訊TBS瀏覽器WebView的教程與注意的地方

    Android在項(xiàng)目中接入騰訊TBS瀏覽器WebView的教程與注意的地方

    今天小編就為大家分享一篇關(guān)于Android在項(xiàng)目中接入騰訊TBS瀏覽器WebView的教程與注意的地方,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-10-10
  • 詳解Android studio 3+版本apk安裝失敗問(wèn)題

    詳解Android studio 3+版本apk安裝失敗問(wèn)題

    這篇文章主要介紹了詳解Android studio 3+版本apk安裝失敗問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04

最新評(píng)論