国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術文章
文章詳情頁

Android 自定義 View 中使用 Spannable的實例詳解

瀏覽:18日期:2022-09-24 08:57:58

我們都知道 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. 定義自定義屬性

<?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; // 圓弧進度顏色 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的文章就介紹到這了,更多相關Android 使用 Spannable內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Android
相關文章:
主站蜘蛛池模板: 国产黄色一级网站 | 亚洲欧美一区二区三区孕妇 | 国产tv在线| 成人精品在线 | 国产精品久久久久久久久岛 | 伊人久色 | 国产亚洲人成网站在线观看不卡 | 看一级毛片 | 欧美国产日韩在线观看 | 国产精品日韩欧美一区二区 | 91情国产l精品国产亚洲区 | 国产菲菲视频在线观看 | 中文字幕一区二区小泽玛利亚 | 久久精品视频99精品视频150 | 久久精品国产一区 | 亚洲国产成人久久综合一区77 | 自拍偷自拍亚洲精品一区 | 牲欧美 | 99久久精品国产一区二区三区 | 正在播放国产精品 | 亚洲精品aaa | 成 人 黄 色 视频播放16 | 99久久国产综合精品网成人影院 | 国产精品色午夜视频免费看 | 欧美性猛交xxxx免费看手交 | 欧美综合成人网 | 荡公乱妇蒂芙尼中文字幕 | 国产精品网站 夜色 | 国产舐足视频在线观看 | 国产成人久久精品二区三区牛 | 久草视频福利资源站 | 免费一区二区三区 | 成人亲子乱子伦视频 | 欧美 亚洲 中文字幕 | 免费国产高清视频 | 一级毛片中国 | 国产盗摄一区二区 | 免费国产黄网站在线观看视频 | 亚洲欧美一区二区三区久本道 | 久久久免费观看 | 欧美日韩国产在线观看一区二区三区 |