工作中有这样一个需求:

打开时动态添加,不知道有多少行,那就开动脑经:在 xml 中写的话,又不确定有多少,那就在代码中 addView,但是呢,需求中又有很多处的 UI 布局也是这样的样式(左右 text 要根据情况修改),当然,一个LinearLayout 包两个 TextView 不难搞,但能不能自定义一个 TextView,简单复用 …

说干就干!

自定义view也有很多种解决方案,可以继承 View、LinearLayout、TextView 等等等等,这里本人继承 TextView,运用一些原先的属性,偷偷懒:

/*** @author 小侨* @desc 左右两边显示 text的 TextView* <p>* 参考:* http://hencoder.com/ui-1-3/* http://blog.csdn.net/xmxkf/article/details/51454685*/public class RightAndLeftTextView extends android.support.v7.widget.AppCompatTextView {/*** PS:TextView有默认 TextSize,setXxxSize时会有视差,所以setXxxText前设置为左右之中最大的 TextSize*      -- xml中:android:textSize="xxsp"*      -- 代码中:setTextSize(TypedValue.COMPLEX_UNIT_SP, xx);*/// 文本private String mLeftText;private String mRightText;// 文本颜色private int mLeftTextColor;private int mRightTextColor;// 文本大小private float mLeftTextSize;private float mRightTextSize;// Paintprivate TextPaint mPaint;// 宽高private int mWidth;private int mHalfWidth;private int mRightTextWidth;private int mLeftTextWidth;private int mRightTextX;public RightAndLeftTextView(Context context) {this(context, null);}public RightAndLeftTextView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public RightAndLeftTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);// 获取自定义属性的值TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RightAndLeftTextView, defStyleAttr, 0);mLeftText = a.getString(R.styleable.RightAndLeftTextView_left_text);mLeftTextColor = a.getColor(R.styleable.RightAndLeftTextView_left_color, Color.BLACK);mLeftTextSize = a.getDimension(R.styleable.RightAndLeftTextView_left_size, 100);mRightText = a.getString(R.styleable.RightAndLeftTextView_right_text);mRightTextColor = a.getColor(R.styleable.RightAndLeftTextView_right_color, Color.BLACK);mRightTextSize = a.getDimension(R.styleable.RightAndLeftTextView_right_size, 100);// 注意回收a.recycle();mPaint = new TextPaint();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = getMeasuredWidth();mHalfWidth = mWidth / 2;}@Overrideprotected void onDraw(Canvas canvas) {drawRightText(canvas);drawLeftText(canvas);// 设置默认文本大小if (mLeftTextSize < mRightTextSize) {setTextSize(TypedValue.COMPLEX_UNIT_PX, mRightTextSize);} else {setTextSize(TypedValue.COMPLEX_UNIT_PX, mLeftTextSize);}// 设置行数if (mLeftTextWidth >= mHalfWidth || mRightTextWidth >= mHalfWidth) {if (mLeftTextWidth < mRightTextWidth) {if ((mRightTextWidth % mHalfWidth) > 0) {setLines(mRightTextWidth / mHalfWidth + 1);} else {setLines(mRightTextWidth / mHalfWidth);}} else if (mRightTextWidth < mHalfWidth) {if ((mLeftTextWidth % (mRightTextX)) > 0) {setLines(mLeftTextWidth / mRightTextX + 1);} else {setLines(mLeftTextWidth / mRightTextX);}} else {if ((mLeftTextWidth % mHalfWidth) > 0) {setLines(mLeftTextWidth / mHalfWidth + 1);} else {setLines(mLeftTextWidth / mHalfWidth);}}}}/*** 左边 text*/private void drawLeftText(Canvas canvas) {mPaint.setTextSize(mLeftTextSize);mPaint.setColor(mLeftTextColor);mLeftTextWidth = (int) mPaint.measureText(mLeftText);// 绘制文字,不能换行// canvas.drawText(mLeftText, 0, mPaint.getTextSize(), mPaint);// 绘制文字,能换行canvas.save();canvas.translate(0, 0);StaticLayout staticLayout = new StaticLayout(mLeftText, mPaint, mRightTextX, Layout.Alignment.ALIGN_NORMAL, 1, 0, true);staticLayout.draw(canvas);canvas.restore();}/*** 右边 text*/private void drawRightText(Canvas canvas) {mPaint.setTextSize(mRightTextSize);mPaint.setColor(mRightTextColor);mRightTextWidth = (int) mPaint.measureText(mRightText);// 绘制文字,不能换行// canvas.drawText(mRightText, mWidth - mRightTextWidth, mHeight, mPaint);// 绘制文字,能换行canvas.save();StaticLayout staticLayout;// 左右两边的 text长度如果超过一半 mWidth就换行if (mRightTextWidth >= mHalfWidth) {mRightTextX = mHalfWidth;canvas.translate(mRightTextX, 0);staticLayout = new StaticLayout(mRightText, mPaint, mHalfWidth, Layout.Alignment.ALIGN_NORMAL, 1, 0, true);} else {mRightTextX = mWidth - mRightTextWidth;canvas.translate(mRightTextX, 0);staticLayout = new StaticLayout(mRightText, mPaint, mRightTextWidth, Layout.Alignment.ALIGN_NORMAL, 1, 0, true);}staticLayout.draw(canvas);canvas.restore();}public String getLeftText() {return mLeftText;}public void setLeftText(String leftText) {mLeftText = leftText;invalidate();}public String getRightText() {return mRightText;}public void setRightText(String rightText) {mRightText = rightText;invalidate();}public int getLeftTextColor() {return mLeftTextColor;}public void setLeftTextColor(int leftTextColor) {mLeftTextColor = leftTextColor;invalidate();}public int getRightTextColor() {return mRightTextColor;}public void setRightTextColor(int rightTextColor) {mRightTextColor = rightTextColor;invalidate();}public float getLeftTextSize() {return mLeftTextSize;}public void setLeftTextSize(float leftTextSize) {mLeftTextSize = leftTextSize;invalidate();}public float getRightTextSize() {return mRightTextSize;}public void setRightTextSize(float rightTextSize) {mRightTextSize = rightTextSize;invalidate();}
}

以下是 attrs.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="RightAndLeftTextView"><attr name="left_text" format="string"/><attr name="left_color" format="color"/><attr name="left_size" format="dimension"/><attr name="right_text" format="string"/><attr name="right_color" format="color"/><attr name="right_size" format="dimension"/></declare-styleable>
</resources>

注意点一:自定义属性,包括左右 text、textSize、textColor

// 获取自定义属性的值TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RightAndLeftTextView, defStyleAttr, 0);mLeftText = a.getString(R.styleable.RightAndLeftTextView_left_text);mLeftTextColor = a.getColor(R.styleable.RightAndLeftTextView_left_color, Color.BLACK);mLeftTextSize = a.getDimension(R.styleable.RightAndLeftTextView_left_size, 100);mRightText = a.getString(R.styleable.RightAndLeftTextView_right_text);mRightTextColor = a.getColor(R.styleable.RightAndLeftTextView_right_color, Color.BLACK);mRightTextSize = a.getDimension(R.styleable.RightAndLeftTextView_right_size, 100);// 注意回收a.recycle();

注意点二:用 StaticLayout 绘制能换行的文字

本来没考虑的,因为需求没有,但为了适配性更好,说不定有人用了特大字体呢 …

// 绘制文字,不能换行// canvas.drawText(mLeftText, 0, mPaint.getTextSize(), mPaint);// 绘制文字,能换行canvas.save();canvas.translate(0, 0);StaticLayout staticLayout = new StaticLayout(mLeftText, mPaint, mRightTextX, Layout.Alignment.ALIGN_NORMAL, 1, 0, true);staticLayout.draw(canvas);canvas.restore();

注意点三:先绘制右边 text

要先绘制右边 text,再根据右边 text 的位置来绘制左边 text,可以规定右边 text 所占宽度不超过多少,使实际效果更好看

// 左右两边的 text长度如果超过一半 mWidth就换行if (mRightTextWidth >= mHalfWidth) {mRightTextX = mHalfWidth;canvas.translate(mRightTextX, 0);staticLayout = new StaticLayout(mRightText, mPaint, mHalfWidth, Layout.Alignment.ALIGN_NORMAL, 1, 0, true);} else {mRightTextX = mWidth - mRightTextWidth;canvas.translate(mRightTextX, 0);staticLayout = new StaticLayout(mRightText, mPaint, mRightTextWidth, Layout.Alignment.ALIGN_NORMAL, 1, 0, true);}

注意点四:设置文本大小及行数

TextView能通过文本大小及多少来计算高度,但是这里是通过canvas直接绘制的,谁让我比较懒不自己计算高度(其实是水平有限),所以要通过TextView本身的setTextSize()来让TextView知道:

// 设置默认文本大小if (mLeftTextSize < mRightTextSize) {setTextSize(TypedValue.COMPLEX_UNIT_PX, mRightTextSize);} else {setTextSize(TypedValue.COMPLEX_UNIT_PX, mLeftTextSize);}

文本行数也是一样的道理:

// 设置行数if (mLeftTextWidth >= mHalfWidth || mRightTextWidth >= mHalfWidth) {if (mLeftTextWidth < mRightTextWidth) {if ((mRightTextWidth % mHalfWidth) > 0) {setLines(mRightTextWidth / mHalfWidth + 1);} else {setLines(mRightTextWidth / mHalfWidth);}} else if (mRightTextWidth < mHalfWidth) {if ((mLeftTextWidth % (mRightTextX)) > 0) {setLines(mLeftTextWidth / mRightTextX + 1);} else {setLines(mLeftTextWidth / mRightTextX);}} else {if ((mLeftTextWidth % mHalfWidth) > 0) {setLines(mLeftTextWidth / mHalfWidth + 1);} else {setLines(mLeftTextWidth / mHalfWidth);}}}

注意点五:动态 set 的时候要刷新

public void setLeftText(String leftText) {mLeftText = leftText;invalidate();}

效果:

实际应用中有很多问题:

问题一 :TextView 有默认 TextSize,如果是先在 xml 中应用了,然后在代码中 set 修改文本大小,setXxxSize 时会有视差,肉眼看上去会有明显的抖动,所以可以在 xml 中运用 android:textSize=“xxsp” 设置成最大的文本 size,就没有抖动了

问题二 :当文字超过三行时,可能出现后几个文字显示不全的问题,目前还不知道原因在哪,要捋一捋

问题三 :如果左右文字加起来刚好占了一行,没有做间隔处理,后补

现在想一想,还有更好的方案能解决这个需求,且本方案还有很多需要改进的地方,但是呢,通过前些日子的修稿,确实感受良多,不断出现问题,刚开始总会想“这样就好了”,但又觉得改改还能更好,改改吧,不是最好,过程胜似最好 …

实践是检验真理的唯一标准,退堂!


参考文章:
http://hencoder.com/ui-1-3/
http://blog.csdn.net/xmxkf/article/details/51454685

Android 自定义 View:左右两边显示 text 的 TextView(RightAndLeftTextView)相关推荐

  1. android 两边圆角,Android自定义View实现带4圆角或者2圆角的效果

    1 问题 实现任意view经过自定义带4圆角或者2圆角的效果 2 原理 1) 实现view 4圆角 我们只需要把左边的图嵌入到右边里面去,最终显示左边的图就行. 2) 实现view上2圆角 我们只需要 ...

  2. android多行文字正中间显示,Android自定义View五(绘制文本大小、多行多列居中)...

    一.绘制文本 在Canvas中绘制文本,使用前面文章的坐标系 1.drawText的几种方法 public void drawText (String text, float x, float y, ...

  3. android lrc 歌词view,自定义View强势来袭,用自定义View实现歌词显示控件下篇之自定义LyricView的实现...

    在上篇中,我与大家分享了关于如何进行*.lrc歌词文件的解析,以及将解析完成后的歌词展示在镶嵌在ScrollView中的TextView上,就这样而言,一个简单的歌词显示功能也就实现了. 但是,如何才 ...

  4. Android 自定义View

    [Android 自定义View] Android 自定义View 自定义View基础 自定义TextView 继承View重写onDraw方法 View的构造方法 自定义属性 创建attrsxml文 ...

  5. Android自定义View之画圆环(进阶篇:圆形进度条)

    前言: 如果你想读懂或者更好的理解本篇文章关于自定义圆环或圆弧的内容.请你务必提前阅读下Android自定义View之画圆环(手把手教你如何一步步画圆环).在这篇文章中,详细描述了最基本的自定义圆环的 ...

  6. Android 自定义View实现环形带刻度颜色渐变的进度条

    上次写了一篇Android 自定义View实现环形带刻度的进度条,这篇文章就简单了,只是在原来的基础上加一个颜色渐变. 按照惯例,我们先来看看效果图 一.概述 1.相比于上篇文章,这里我们的颜色渐变主 ...

  7. Android自定义View —— TypedArray

    在上一篇中Android 自定义View Canvas -- Bitmap写到了TypedArray 这个属性 下面也简单的说一下TypedArray的使用 TypedArray 的作用: 用于从该结 ...

  8. android代码实现手机加速功能,Android自定义View实现内存清理加速球效果

    Android自定义View实现内存清理加速球效果 发布时间:2020-09-21 22:21:57 来源:脚本之家 阅读:105 作者:程序员的自我反思 前言 用过猎豹清理大师或者相类似的安全软件, ...

  9. 自定义圆形倒计时Android,Android自定义View倒计时圆

    本文实例为大家分享了Android自定义View倒计时圆的具体代码,供大家参考,具体内容如下 创建attr 创建DisplayUtil 类 import android.content.Context ...

最新文章

  1. 依然持有比特币,Roger Ver谈投资心经
  2. 滚动条滚动加载图片或则请求的实现方法
  3. 产品体验分析之7步走(附PPT)
  4. vim does not map customized key?
  5. hdu4821 字符串hash
  6. 支持串行隔离级别_从0到1理解数据库事务(上):并发问题与隔离级别
  7. httpinvoker
  8. JavaScript数据类型之数据类型之间的转换(6)
  9. 串结构练习--字符串匹配
  10. Excel的设置 .net
  11. 《Pro SQL Server Internals, 2nd edition》的CHAPTER 2 Tables and Indexes中的Clustered Indexes一节...
  12. 域渗透TIPS:获取LAPS管理员密码
  13. 仿链家地图找房_仿链家地图找房的简单实现
  14. 1-十四烷基-3-甲基咪唑六氟磷酸盐([C14MIm][PF6])修饰纳米SiO2二氧化硅(mg级瓶装)
  15. 血管老化30岁就开始!别怕,吃它就能搞定,让血管保持年轻~
  16. 电脑商城-02-注册
  17. 9、XAML名称空间详解
  18. sklearn聚类之OPTICS算法
  19. seo模拟点击软件_SEO快排
  20. 机器人唱歌bgm_Soul app里面机器人匹配的那首bgm是什么呀?好好听!!!求玩过soul的大神告知!!...

热门文章

  1. scala implicit - implicit parameters spark 应用
  2. 电视剧版----《致青春》经典语录
  3. MQ如何保证分布式事务的最终一致性
  4. AutoEventWireup=false导致Page_Load事件未执行
  5. Js清除指定cookie
  6. JavaScript判断语句
  7. cubemx 读卡器_STM32CubeMX基于SD卡的FATFS文件系统测试
  8. Win7下无损分区和分区调整
  9. ip ubuntu如何修改master_ubuntu16.04 设置静态ip
  10. node 多版本管理(mac)