真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Android如何使用自定義View中Spannable

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

為鐵東等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及鐵東網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計、鐵東網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

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

Android如何使用自定義View中Spannable

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

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

/**
 * A base class that manages text layout in visual elements on
 * the screen.
 * 

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 是一個抽象類,有三個子類,可以實現(xiàn)一些自動換行的顯示效果。

  • BoringLayout
  • DynamicLayout
  • StaticLayout

實現(xiàn)代碼

1. 定義自定義屬性

<?xml version="1.0" encoding="utf-8"?>

 
  
  
  
  
  
  
  
  
 

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 繪制文字時,默認(rèn)畫在Canvas的(0,0)點(diǎn)位置,所以居中繪制居中位置,需要將畫布 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();
 }
 /**
  * 對外提供方法,設(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. 在布局中引用

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


網(wǎng)頁標(biāo)題:Android如何使用自定義View中Spannable
URL標(biāo)題:http://weahome.cn/article/pdpcjj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部