成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

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

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

瀏覽:75日期: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
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
久久99国产精品麻豆| 日韩欧美精品在线视频| 欧美精品少妇一区二区三区| 国内精品伊人久久久久av一坑| 亚洲一区成人| 亚洲美女视频在线观看| 亚洲视频久久| 国产精品麻豆一区二区| 欧美激情第10页| 久久久久久一级片| 成人免费视频播放| 日韩欧美一区在线| 激情av一区| 国产精品美女久久久久高潮| 色综合一区二区三区| 国产亚洲精品中文字幕| 97se狠狠狠综合亚洲狠狠| 欧美α欧美αv大片| 成人精品电影在线观看| 欧美v日韩v国产v| 成人国产在线观看| 精品国产青草久久久久福利| 97精品视频在线观看自产线路二| 久久久午夜电影| 欧美破处大片在线视频| 亚洲欧洲日韩女同| 一区二区三区四区国产| 亚洲综合一区二区精品导航| 99精品国产福利在线观看免费 | 亚洲黄色av一区| 国产伦精品一区二区三| 亚洲欧洲日本在线| 久久精品亚洲| 国产成人在线网站| 国产精品私房写真福利视频| 国产色综合网| 精品中文字幕一区二区| 精品欧美一区二区三区精品久久| 欧美精品九九| 亚洲精品视频观看| 久久亚洲风情| 国产精品1024久久| 欧美激情在线看| 亚洲视频成人| 精品一二线国产| 欧美精品一区二区蜜臀亚洲| 欧美伊人影院| 亚洲一区二区免费视频| 欧美在线free| av在线这里只有精品| 自拍偷自拍亚洲精品播放| 久久最新视频| 高清不卡在线观看av| 国产精品你懂的在线| 男女精品视频| 国产激情一区二区三区| 国产欧美精品一区aⅴ影院| 一本久久综合| 狠狠网亚洲精品| 国产欧美日韩在线看| 亚洲一区二区伦理| 国产一区二区91| 国产精品私房写真福利视频| 久久一区激情| 成人av网站在线| 亚洲欧美另类久久久精品 | 欧美日韩国产综合视频在线| 亚洲精品乱码久久久久久久久| 欧美伊人久久久久久午夜久久久久| 国产a视频精品免费观看| 国产精品久久久久毛片软件| 在线一区二区三区四区五区| 91麻豆swag| 日本在线播放一区二区三区| 精品国产乱码久久久久久免费| 亚洲日韩成人| 国产综合成人久久大片91| 久久久亚洲精品石原莉奈| 国产亚洲欧美一区二区| 国产成人在线免费| 自拍偷拍欧美精品| 欧美日本乱大交xxxxx| 黄色日韩在线| 国产在线观看一区二区| 中文字幕在线不卡| 6080午夜不卡| 国产亚洲亚洲| 大陆成人av片| 亚洲高清免费视频| 精品少妇一区二区三区视频免付费| 国产视频在线观看一区 | 老鸭窝毛片一区二区三区 | 91麻豆免费看片| 蜜臀av一区二区在线观看| 欧美激情自拍偷拍| 欧美日韩免费一区二区三区视频| 欧美视频网站| 国产一区二区三区免费看 | 久久久精品免费网站| 久久资源av| 欧美日韩天天操| 国产在线国偷精品产拍免费yy| 伊人婷婷欧美激情| 精品嫩草影院久久| 欧美中文字幕一区| 亚洲精品一级| 99久久精品免费观看| 老司机午夜精品| 亚洲精品自拍动漫在线| 亚洲精品在线观看网站| 日本国产一区二区| 亚洲日本成人| 91视频国产资源| 狠狠色丁香久久婷婷综合_中| 亚洲男人的天堂在线观看| 精品成人一区二区三区| 在线免费观看不卡av| 99riav国产精品| 91日韩在线专区| 国产精品自拍av| 视频一区在线播放| 亚洲免费在线电影| 国产日韩精品一区| 91精品国产免费| 久久久精品网| 亚洲福利久久| 不卡一区中文字幕| 蜜桃传媒麻豆第一区在线观看| 亚洲图片欧美激情| 国产夜色精品一区二区av| 91精品国产综合久久国产大片| 久久久精品五月天| 影音先锋亚洲电影| 99r精品视频| 国内精品伊人久久久久影院对白| 亚洲午夜精品一区二区三区他趣| 国产精品久久久久久久午夜片| 精品久久久久久最新网址| 欧美少妇xxx| 久久精品一区二区三区中文字幕| 亚洲午夜精品久久| 成人免费视频免费观看| 国产一区二区三区久久悠悠色av| 日本视频免费一区| 国产欧美综合色| 欧美精品一区二区高清在线观看| 7777精品伊人久久久大香线蕉完整版 | 99久久久久免费精品国产 | 91黄色小视频| 亚洲欧美日韩综合国产aⅴ| 国产精品啊啊啊| 91捆绑美女网站| 成人小视频免费观看| 极品瑜伽女神91| 日韩电影一区二区三区| 亚洲免费成人av| 中文字幕在线不卡视频| 欧美激情一区三区| 日本一区二区三区久久久久久久久不| 91精品国产欧美日韩| 欧美精品tushy高清| 欧美日韩亚洲综合在线 欧美亚洲特黄一级 | 国内外精品视频| 精品一区二区三区在线播放视频 | 久久99这里只有精品| 丝袜美腿亚洲综合| 亚洲午夜精品久久久久久久久| 一区二区三区精品视频在线| 日韩伦理av电影| 亚洲品质自拍视频| **欧美大码日韩| 亚洲男人天堂一区| 一区二区理论电影在线观看| 日韩一区中文字幕| 亚洲色欲色欲www| 亚洲欧美电影一区二区| 亚洲精品视频一区| 亚洲va欧美va人人爽| 五月婷婷色综合| 免费的成人av| 国产麻豆精品theporn| 国产精品自拍av| 不卡视频免费播放| 欧美1区视频| 亚洲一级影院| 99爱精品视频| 久久亚洲精选| 久久一二三区| 欧美亚洲国产bt| 欧美一区二区三区人| 久久在线观看免费| 日本一区二区免费在线| **欧美大码日韩| 亚洲一卡二卡三卡四卡| 亚洲aaa精品| 久久激情五月婷婷| 波多野结衣在线一区| 欧美日韩国内| 国产精品欧美日韩一区| 在线观看av不卡|