公司的UI都是些大神,设计起来毫不含糊,怎么好看怎么设计,没办法只能一点点实现着(UI以后给别的团队设计估计会说 某某团队的某某以前作出过了类似的效果 ... 嘎嘎嘎 )

1、根据UI设计有三个重点

a、消息内容是不固定的,视长度而现实不同的效果

b、收起/全文按钮与消息 content的  TextView对齐

c、content textView 消息需要左右都对齐

<实现效果图>

2、自己梳理出的实现思路

a、全文/收起按钮的显示 是通过监听textView 内容(需要自定义 listener)

b、全文/收起按键会触发 textview 的显示, (Textiview 需要添加一个对应设置方法)

c、收起模式下 从UI的层面来看会占据 TextView 的右下方并且保持对齐(这里需要计算出最后一行的width 和 全文/收起 按键长度是否超过了  ATMOST 的最大值,把多出的内容用省略号替换掉)

d、全文模式下   从UI的层面来看会占据 TextView 的右下方并且保持对齐,而且保持textView的显示完全,需要计算并且准确换行

e、每一行的内容确定后需要保持左右靠边对齐

3、写代码(自定义的 FullTextView  关键的实现地方添加注释 ,默认先不考虑padding的值)

public class FullTextView extends AppCompatTextView {/*** 原始数据*/private String oldText;/*** 全文显示内容*/private StringBuffer fullText = new StringBuffer();/*** 缩略显示内容*/private StringBuffer unFullText = new StringBuffer();/*** 通知外部UI 是否显示 全文/收起/不显示  按键*/private FullTextListener listener;/*** 展示全文显示(默认是不显示全文)*/boolean isShowFullText = false;/*** UI 给出缩略显示最大行数为 2*/private final int UN_FULL_MAX_LINE = 2;/*** 最宽 长度*/private int widthSize = 0;String TAG = FullTextView.class.getSimpleName();public FullTextView(Context context) {super(context);}public FullTextView(Context context, AttributeSet attrs) {super(context, attrs);}public FullTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}/*** 设置原始数据* 此处不需要通过setText() 方法来实现,该自定义TextView 的测绘  跟绘制都是通过自定义实现*/public void setShowText(String text) {oldText = text;if (widthSize > 0) {// 消息适用于 adapter 避免view 复用内容也复用了,所以需要重新计算出内容calculateText();updateUI();}}/*** 刷新UI*/private void updateUI() {//触发 onMeasure  onLayoutrequestLayout();//触发  onDrawinvalidate();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int width = MeasureSpec.getSize(widthMeasureSpec);Log.i(TAG, hashCode() + " width == " + width);//目前 默认为ATMOST 方式if (width != 0) {widthSize = width;calculateText();setMeasuredDimension(widthSize, getLineHeight() * (getLinesStr().length - 1) + getFirstBaselineToTopHeight() + getLastBaselineToBottomHeight());}}/*** 每一行的String 以数组的 形式返回** @return*/private String[] getLinesStr() {String[] strings;if (!isShowFullText) {// “\n”  最后时  split 会少一行内容if (unFullText.toString().endsWith("\n")) {unFullText.append(" ");}strings = unFullText.toString().split("\n");} else {if (fullText.toString().endsWith("\n")) {fullText.append(" ");}strings = fullText.toString().split("\n");}return strings;}/*** 计算出 缩略显示的 text*/private void calculateUnFullText() {if (widthSize == 0) return;unFullText = new StringBuffer();Paint tvPaint = getPaint();float tempWidth = 0;//行数计数器int lineCount = 0;for (int cnt = 0; cnt != oldText.length(); ++cnt) {char ch = oldText.charAt(cnt);tempWidth += tvPaint.measureText(String.valueOf(ch));if (tempWidth <= widthSize) {unFullText.append(ch);} else {lineCount++;tempWidth = 0;--cnt;if (lineCount == UN_FULL_MAX_LINE) {break;}unFullText.append("\n");}}// 总行数达不到 2行以上 特殊显示if (lineCount < UN_FULL_MAX_LINE) {listener.onShowFull(FullTextType.DAFAULT);} else {//如果是展示全文不需要处理if (isShowFullText) {listener.onShowFull(FullTextType.FULL);} else {float collapseW = tvPaint.measureText(getContext().getResources().getString(R.string.collapse));float omitW = tvPaint.measureText(getContext().getResources().getString(R.string.omit));String laststr = unFullText.toString().split("\n")[UN_FULL_MAX_LINE - 1];for (int i = 0; i < laststr.length(); i++) {float textW = tvPaint.measureText(laststr.substring(0, laststr.length() - i));if ((textW + collapseW + omitW) <= widthSize) {unFullText = new StringBuffer(unFullText.substring(0, unFullText.length() - i));break;}}unFullText.append(getContext().getResources().getString(R.string.omit));listener.onShowFull(FullTextType.UNFULL);}}}/*** 最后的 收起二字 是否能在最后一行 内显示完全** @return*/private void calculateFullText() {oldText.replace("\n", "");fullText = new StringBuffer();Paint tvPaint = getPaint();float tempWidth = 0;//行数计数器for (int cnt = 0; cnt != oldText.length(); ++cnt) {char ch = oldText.charAt(cnt);tempWidth += tvPaint.measureText(String.valueOf(ch));if (tempWidth <= widthSize) {fullText.append(ch);} else {fullText.append("\n");tempWidth = 0;--cnt;}}float lastlinewidth = (tempWidth + tvPaint.measureText(getContext().getResources().getString(R.string.collapse)));if (lastlinewidth > widthSize) {fullText.append("\n");}}/*** 计算  全文/收起 文本显示内容*/private void calculateText() {calculateFullText();calculateUnFullText();}public boolean isShowFullText() {return isShowFullText;}/*** @param isShowFull 全文/收起 显示* @param updateUI   是否刷新UI*/public void setShowFullText(boolean isShowFull, boolean updateUI) {this.isShowFullText = isShowFull;if (updateUI && fullText.length() > 0 && unFullText.length() > 0 && listener != null) {if (isShowFullText) {listener.onShowFull(FullTextType.FULL);} else {listener.onShowFull(FullTextType.UNFULL);}updateUI();}}public void setFullTextListener(FullTextListener listener) {this.listener = listener;}public interface FullTextListener {void onShowFull(FullTextType type);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);onDrawStrings(canvas, getLinesStr());}/*** 绘制每一行的 text** @param canvas* @param strs*/private void onDrawStrings(Canvas canvas, String[] strs) {//起始 X值float startX = 0;for (int i = 0; i < strs.length; i++) {float baseLine = getBaseline() + (getLineHeight() * i) + getPaddingTop();if (i == strs.length - 1) {startX = 0;canvas.drawText(strs[i], startX, baseLine, getPaint());break;}Log.i(TAG, "onDraw  strs" + i + "]=" + strs[i]);float lineWidth = getPaint().measureText(strs[i]);float pw = (widthSize - lineWidth) / (strs[i].length());startX = pw;for (int j = 0; j < strs[i].length(); j++) {canvas.drawText(String.valueOf(strs[i].charAt(j)), startX, baseLine, getPaint());startX += pw + getPaint().measureText(String.valueOf(strs[i].charAt(j)));}}}}

定义了一个 枚举

public enum FullTextType {/*** 不处理*/DAFAULT,/*** 全文*/FULL,/*** 收起*/UNFULL;
}

adapter 用法关键代码(xml 对齐的可以自己拓展)

 //缓存记录 iTEM 状态 避免view复用 重复if (fullmap.keySet().contains(position)) {holder.content.setShowFullText(fullmap.get(position), false);} else {holder.content.setShowFullText(false, false);}holder.content.setShowText(msgBean.getContent());holder.content.setFullTextListener(new FullTextView.FullTextListener() {@Overridepublic void onShowFull(FullTextType type) {switch (type) {case DAFAULT:holder.item_msg_show_all.setVisibility(View.GONE);break;case FULL:holder.item_msg_show_all.setVisibility(View.VISIBLE);holder.item_msg_show_all.setText(mContext.getResources().getString(R.string.collapse));break;case UNFULL:holder.item_msg_show_all.setVisibility(View.VISIBLE);holder.item_msg_show_all.setText(mContext.getResources().getString(R.string.expand));break;}}});holder.item_msg_show_all.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {boolean bb = !holder.content.isShowFullText();holder.content.setShowFullText(bb, true);fullmap.put(position, bb);}});

整理流程差多就是这样了,需要demo 的可以私信.

自定义收缩TextView相关推荐

  1. 简单实现自定义Android TextView字体

    效果图: 如何做? 引入自定义字体,如果Android工程里面没有assets文件夹,在Android视图下可以右键app,选择New -> Folder -> Assets Folder ...

  2. android 加载ttf流程分析,Android自定义字体 TextView 从SD卡加载TTF字体

    Android自定义字体非常简单,能够从assets和SD卡两处加载标准的ttf字体.要实现自定义字体,只需借助工具类Typeface即可.文末有工程源码. 如果发生了Caused by: java. ...

  3. android 代码设置textview draw,Android 自定义气泡TextView

    效果如下: 可以设置颜色.描边.三角形高度和方向,以向上居中和向下居中为例 气泡.png 实现思路: 使用Canvas绘制气泡形状,因为气泡中间只显示文字,所以我直接继承TextView,重写onDr ...

  4. 自定义DrawableTextView——实现TextView左上右下的点击监听

    在Android开发中我们经常遇到TextView左上右下有图片的UI布局情形,并且各个图片点击后都要做相应的逻辑操作,这种情况下我们首先想到的是利用线性布局或相对布局去排版,然后给每个图片设置id, ...

  5. 翻翻git之---不靠画全靠“演”,好看的自定义TextView translucent-android

    转载请注明出处:王亟亟的大牛之路 P1:废话部分 上周五又没上班所以没怎么写东西,礼拜5 入了条地图,昨天开食了,有时间再去搞两条别的然后再买个缸(家里的缸,鱼啊别的动物已经好多了..次哦)0.0 不 ...

  6. Android尺子布局和自定义TextView

    Android尺子布局和自定义TextView 下面是具体实现: 新建项目:在UI中 <LinearLayout xmlns:android="http://schemas.andro ...

  7. android中弹出消息字体设置,Android如何设置中粗字体——自定义textview

    最近UI出了一版新的UI效果图,里面的标题用的都是中粗字体.这个中粗字体对于ios来说是很容易的,因为ios本省就自带中粗字体,但是对于安卓来说就没那么简单了,因为安卓中的textview只有标准字体 ...

  8. android自定义TextView添加虚线下划线

    目前相关文字下方添加虚线的文章非常少,备选方案有: 文字下方添加一个drawable实现虚线样式 通过spannable方案自定义 通过textview的getpaint实现 实现自定义并绘制 最后还 ...

  9. Android如何设置中粗字体——自定义textview

    最近UI出了一版新的UI效果图,里面的标题用的都是中粗字体.这个中粗字体对于ios来说是很容易的,因为ios本省就自带中粗字体,但是对于安卓来说就没那么简单了,因为安卓中的textview只有标准字体 ...

最新文章

  1. 关于C语言中的malloc和free函数的用法
  2. Oracle 11g 新特性 -- 只读表(read-only table)说明
  3. 系统集成项目管理之项目采购管理
  4. 两边双虚线是什么意思_单黄线和双黄线有什么不同?很多人都记不对,被扣分都不知道...
  5. 百步斋诗钞【绝句四首】
  6. Ruby 学习笔记3
  7. 域名的MX设置及校验方法
  8. .NET LINQ分析AWS ELB日志避免996
  9. CreateProcess的使用方法
  10. oracle sga pga mysql_oracle实例内存(SGA和PGA)调整-xin
  11. 新手须知,前端该如何与后端合作?
  12. web前端网页设计作业_如何学习网页前端设计培训?
  13. 微信小程序——聊天小程序(从搭建到结束)
  14. 计算机专业数学建模结课论文,大学生数学建模论文范文
  15. vant ,vue 图片上传压缩
  16. Linux查看目录大小——du命令
  17. 163个人电子邮箱如何注册申请,解密163个人邮箱如何注册?
  18. 《犯罪心理》第一至第六季 名人名言 全
  19. Coreldraw2022cdr新版更新矢量图设计
  20. 腾讯面试--测试工程师社会招聘面试经历

热门文章

  1. 我的购物车类,支持自定义列及自动金额计算
  2. PHP的四种运行模式
  3. Stale Element Reference Exception
  4. Thinking In Java学习笔记
  5. ajax必填项验证,jQuery验证 - 通过MVC2中的ajax动态添加必填字段
  6. i7 6700k linux,i7 6700与i7 6700K哪个好?i7-6700和i7-6700K区别对比
  7. c语言scandir函数排序,关于C ++:如何在scandir中参数化选择函数
  8. 软件or硬件?硬件的前途到底在哪里?
  9. 论文笔记--Goat: Fine-tuned LLaMA Outperforms GPT-4 on Arithmetic Tasks
  10. 行业报告丨引领产业数字化转型,数字化场景革命十大洞察(附下载)