自定义收缩TextView
公司的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相关推荐
- 简单实现自定义Android TextView字体
效果图: 如何做? 引入自定义字体,如果Android工程里面没有assets文件夹,在Android视图下可以右键app,选择New -> Folder -> Assets Folder ...
- android 加载ttf流程分析,Android自定义字体 TextView 从SD卡加载TTF字体
Android自定义字体非常简单,能够从assets和SD卡两处加载标准的ttf字体.要实现自定义字体,只需借助工具类Typeface即可.文末有工程源码. 如果发生了Caused by: java. ...
- android 代码设置textview draw,Android 自定义气泡TextView
效果如下: 可以设置颜色.描边.三角形高度和方向,以向上居中和向下居中为例 气泡.png 实现思路: 使用Canvas绘制气泡形状,因为气泡中间只显示文字,所以我直接继承TextView,重写onDr ...
- 自定义DrawableTextView——实现TextView左上右下的点击监听
在Android开发中我们经常遇到TextView左上右下有图片的UI布局情形,并且各个图片点击后都要做相应的逻辑操作,这种情况下我们首先想到的是利用线性布局或相对布局去排版,然后给每个图片设置id, ...
- 翻翻git之---不靠画全靠“演”,好看的自定义TextView translucent-android
转载请注明出处:王亟亟的大牛之路 P1:废话部分 上周五又没上班所以没怎么写东西,礼拜5 入了条地图,昨天开食了,有时间再去搞两条别的然后再买个缸(家里的缸,鱼啊别的动物已经好多了..次哦)0.0 不 ...
- Android尺子布局和自定义TextView
Android尺子布局和自定义TextView 下面是具体实现: 新建项目:在UI中 <LinearLayout xmlns:android="http://schemas.andro ...
- android中弹出消息字体设置,Android如何设置中粗字体——自定义textview
最近UI出了一版新的UI效果图,里面的标题用的都是中粗字体.这个中粗字体对于ios来说是很容易的,因为ios本省就自带中粗字体,但是对于安卓来说就没那么简单了,因为安卓中的textview只有标准字体 ...
- android自定义TextView添加虚线下划线
目前相关文字下方添加虚线的文章非常少,备选方案有: 文字下方添加一个drawable实现虚线样式 通过spannable方案自定义 通过textview的getpaint实现 实现自定义并绘制 最后还 ...
- Android如何设置中粗字体——自定义textview
最近UI出了一版新的UI效果图,里面的标题用的都是中粗字体.这个中粗字体对于ios来说是很容易的,因为ios本省就自带中粗字体,但是对于安卓来说就没那么简单了,因为安卓中的textview只有标准字体 ...
最新文章
- 关于C语言中的malloc和free函数的用法
- Oracle 11g 新特性 -- 只读表(read-only table)说明
- 系统集成项目管理之项目采购管理
- 两边双虚线是什么意思_单黄线和双黄线有什么不同?很多人都记不对,被扣分都不知道...
- 百步斋诗钞【绝句四首】
- Ruby 学习笔记3
- 域名的MX设置及校验方法
- .NET LINQ分析AWS ELB日志避免996
- CreateProcess的使用方法
- oracle sga pga mysql_oracle实例内存(SGA和PGA)调整-xin
- 新手须知,前端该如何与后端合作?
- web前端网页设计作业_如何学习网页前端设计培训?
- 微信小程序——聊天小程序(从搭建到结束)
- 计算机专业数学建模结课论文,大学生数学建模论文范文
- vant ,vue 图片上传压缩
- Linux查看目录大小——du命令
- 163个人电子邮箱如何注册申请,解密163个人邮箱如何注册?
- 《犯罪心理》第一至第六季 名人名言 全
- Coreldraw2022cdr新版更新矢量图设计
- 腾讯面试--测试工程师社会招聘面试经历
热门文章
- 我的购物车类,支持自定义列及自动金额计算
- PHP的四种运行模式
- Stale Element Reference Exception
- Thinking In Java学习笔记
- ajax必填项验证,jQuery验证 - 通过MVC2中的ajax动态添加必填字段
- i7 6700k linux,i7 6700与i7 6700K哪个好?i7-6700和i7-6700K区别对比
- c语言scandir函数排序,关于C ++:如何在scandir中参数化选择函数
- 软件or硬件?硬件的前途到底在哪里?
- 论文笔记--Goat: Fine-tuned LLaMA Outperforms GPT-4 on Arithmetic Tasks
- 行业报告丨引领产业数字化转型,数字化场景革命十大洞察(附下载)