android开发游记:textview超过长度点击展开自动滚动(在一个TextView中实现,不增加布局复杂度)
2017-12-26 11:27
1076 查看
最近有需求需要在一个有限高度的页面上显示超过其高度的文字,当文字超过最大行之后显示省略号和查看更多,然后点击查看更多显示完整的信息,并且可以滚动。
先看效果图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/02/59e33b7c93fec68654afddaca2a8298f)
功能很简单,网上搜的有人使用了scrollview来滚动,再添加一个按钮”查看更多”,然后点击后把消息全部展示,再把按钮隐藏。
但是这样做不是觉得很复杂,其实所有的工作在一个textView里就可以完成了,包括滚动效果,包括查看更多的按钮。这些都可以在同一个textView里处理完,先上代码,后面再解释其原理。
我封装成了一个工具类,使用该工具类来处理TextView的显示逻辑
使用方法:
导入下面的工具类MoreTextUtil,在你需要设置TextView拥有展开效果的时候添加下面代码:
2
你也可以这样,使用重载的方法:
默认最大可显示行数为5行,如果需要自定义就给自己的TextView的布局加上下面的属性:
用法很简单吧,下面上源码:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
代码中的注释很清楚,说下重点:
代码中为什么要使用布局变化监听器呢,如下:
2
3
4
原因是TextView会根据字符的排版规则自动换行,这种换行受字体大小的影响,而且英文字母符号中文等不同字符占的宽并不同,而且TextView还会自动匹配单词选择性换行,所以我们几乎无法通过一个字符串计算出TextView会在什么时候换行,我们也无法计算出在字符串的哪个位置会因为显示不下而出现截断。
那么我们就换一种方式,直接把字符串绘制到TextView中,在TextView生成布局渲染完成后把字符设置到页面前一刻再回调我们的方法,这样我们就可以得到TextView具体绘制了多少行,每行的字符是什么,这也就是为什么要使用ViewTreeObserver 添加 OnGlobalLayoutListener 的原因。在onGlobalLayout回调方法中完成我们的业务逻辑。
但是值得注意的是,OnGlobalLayoutListener 会在绘制过程中被调用多少,而我们的业务逻辑只需要处理一次就可以了,为了避免不必要的性能损失,我们得加以控制,通过hasMesure 这个布尔变量来控制代码只执行一次。
另外一个重要的地方就是,我们没有添加按钮,那就以为着我们的TextView必须要支持局部点击事件,就是说,点击“查看更多”的时候要有响应,而点其他地方没有。还好TextView的SpannableString (复合文本) 支持多事件和样式的处理,如下:
2
3
4
5
6
这里就使用了复合文本格式来设置局部的点击事件,方法原型如下:
what 参数可以设置一个监听器
start 指定了设置的字符的开始位置
end 是指定字符的结束位置
flags 是间隔模式,SPAN_EXCLUSIVE_EXCLUSIVE表示不影响前后相邻的字符
接着看复合文本事件监听器:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
构造方法我传入了完整的字符串和一个颜色值,当点击后把显示的字符串换成完整的字符,并设置可以滚动就ok,至于颜色值,我希望“查看更多”这4个字拥有不同的颜色,当然你不设置也没有什么关系,丑一点而已。
在点击事件执行之前,会先调用updateDrawState(TextPaint ds)方法设置绘制格式,在这里设置颜色和取消下划线,如果需要其他特殊效果的话也在这里处理。
觉得不错的下面有个顶,可以点一下 :)
先看效果图:
功能很简单,网上搜的有人使用了scrollview来滚动,再添加一个按钮”查看更多”,然后点击后把消息全部展示,再把按钮隐藏。
但是这样做不是觉得很复杂,其实所有的工作在一个textView里就可以完成了,包括滚动效果,包括查看更多的按钮。这些都可以在同一个textView里处理完,先上代码,后面再解释其原理。
我封装成了一个工具类,使用该工具类来处理TextView的显示逻辑
使用方法:
导入下面的工具类MoreTextUtil,在你需要设置TextView拥有展开效果的时候添加下面代码:
textView.setText("你要显示的内容"); MoreTextUtil.setMore(textView);1
2
你也可以这样,使用重载的方法:
MoreTextUtil.setMore(textView,"你要显示的内容");1
默认最大可显示行数为5行,如果需要自定义就给自己的TextView的布局加上下面的属性:
android:maxLines="9" //最多显示9行1
用法很简单吧,下面上源码:
package com.shelwee.update.utils; import android.annotation.SuppressLint; import android.text.Layout; import android.text.SpannableString; import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils.TruncateAt; import android.text.method.LinkMovementMethod; import android.text.method.ScrollingMovementMethod; import android.text.style.ClickableSpan; import android.view.View; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.TextView; import com.shelwee.updater.R; public class MoreTextUtil { public static boolean hasMesure = false; //是否已经执行过一次 public static void setMore(TextView textV,String content){ textV.setText(content); setMore(textV,"...","查看更多"); } public static void setMore(TextView textV){ setMore(textV,"...","查看更多"); } @SuppressLint("NewApi") public static void setMore(final TextView textV, final String ellipsis, final String strmore) { if (textV == null) { return; } if (2147483647 == textV.getMaxLines()) textV.setMaxLines(5); textV.setEllipsize(TruncateAt.END); textV.setVerticalScrollBarEnabled(true); hasMesure = false; //添加布局变化监听器,view 布局完成时调用,每次view改变时都会调用 ViewTreeObserver vto = textV.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (!hasMesure) { int maxLines = textV.getMaxLines(); int lines = textV.getLineCount(); //如果文字的行数超过最大行数,展示缩略的textview if (lines >= maxLines) { Layout layout=textV.getLayout(); String str=layout.getText().toString(); int end = layout.getLineEnd(maxLines-2); str = str.substring(0, end); //缩略的文字 String strall = textV.getText().toString(); //完整的文字 hasMesure = true; SpannableString spanstr; //如果以换行符结尾,则不再换行 if (str.endsWith("\n")) { spanstr = new SpannableString(str + ellipsis + strmore); }else { spanstr = new SpannableString(str + "\n" + ellipsis + strmore); } //设置“查看更多”的点击事件 spanstr.setSpan(new MyClickableSpan(strall,textV.getResources().getColor(android.R.color.holo_green_dark)), spanstr.length() - strmore.length(), spanstr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textV.setText(spanstr); //移除默认背景色 textV.setHighlightColor(textV.getResources().getColor(android.R.color.transparent)); textV.setMovementMethod(LinkMovementMethod.getInstance()); } } } }); } static class MyClickableSpan extends ClickableSpan{ private String str; private int color; public MyClickableSpan(String str,int color) { this.str = str; this.color = color; } @Override public void onClick(View view) { ((TextView)view).setMovementMethod(new ScrollingMovementMethod()); ((TextView)view).setText(str); } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(color); //设置“查看更多”字体颜色 ds.setUnderlineText(false); //设置“查看更多”无下划线,默认有 ds.clearShadowLayer(); } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
代码中的注释很清楚,说下重点:
代码中为什么要使用布局变化监听器呢,如下:
ViewTreeObserver vto = textV.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){ .... });1
2
3
4
原因是TextView会根据字符的排版规则自动换行,这种换行受字体大小的影响,而且英文字母符号中文等不同字符占的宽并不同,而且TextView还会自动匹配单词选择性换行,所以我们几乎无法通过一个字符串计算出TextView会在什么时候换行,我们也无法计算出在字符串的哪个位置会因为显示不下而出现截断。
那么我们就换一种方式,直接把字符串绘制到TextView中,在TextView生成布局渲染完成后把字符设置到页面前一刻再回调我们的方法,这样我们就可以得到TextView具体绘制了多少行,每行的字符是什么,这也就是为什么要使用ViewTreeObserver 添加 OnGlobalLayoutListener 的原因。在onGlobalLayout回调方法中完成我们的业务逻辑。
但是值得注意的是,OnGlobalLayoutListener 会在绘制过程中被调用多少,而我们的业务逻辑只需要处理一次就可以了,为了避免不必要的性能损失,我们得加以控制,通过hasMesure 这个布尔变量来控制代码只执行一次。
另外一个重要的地方就是,我们没有添加按钮,那就以为着我们的TextView必须要支持局部点击事件,就是说,点击“查看更多”的时候要有响应,而点其他地方没有。还好TextView的SpannableString (复合文本) 支持多事件和样式的处理,如下:
//设置“查看更多”的点击事件 spanstr.setSpan(new MyClickableSpan(strall,textV.getResources().getColor(R.color.cc_orage)), spanstr.length() - strmore.length(), spanstr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textV.setText(spanstr);1
2
3
4
5
6
这里就使用了复合文本格式来设置局部的点击事件,方法原型如下:
spanstr.setSpan(Object what,int start,int end,int flags)1
what 参数可以设置一个监听器
start 指定了设置的字符的开始位置
end 是指定字符的结束位置
flags 是间隔模式,SPAN_EXCLUSIVE_EXCLUSIVE表示不影响前后相邻的字符
接着看复合文本事件监听器:
static class MyClickableSpan extends ClickableSpan{ private String str; private int color; public MyClickableSpan(String str,int color) { this.str = str; this.color = color; } @Override public void onClick(View view) { ((TextView)view).setMovementMethod(new ScrollingMovementMethod()); ((TextView)view).setText(str); } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(color); //设置“查看更多”字体颜色 ds.setUnderlineText(false); //设置“查看更多”无下划线,默认有 ds.clearShadowLayer(); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
构造方法我传入了完整的字符串和一个颜色值,当点击后把显示的字符串换成完整的字符,并设置可以滚动就ok,至于颜色值,我希望“查看更多”这4个字拥有不同的颜色,当然你不设置也没有什么关系,丑一点而已。
在点击事件执行之前,会先调用updateDrawState(TextPaint ds)方法设置绘制格式,在这里设置颜色和取消下划线,如果需要其他特殊效果的话也在这里处理。
觉得不错的下面有个顶,可以点一下 :)
相关文章推荐
- android开发游记:textview超过长度点击展开自动滚动(在一个TextView中实现,不增加布局复杂度)
- android TextView 垂直自动滚动字幕实现
- android TextView 垂直自动滚动字幕实现
- android开发 textview根据字数长度自动调整字体大小
- android Textview 实现展开收缩功能+部分文字点击 (SpannableString)
- Android文字自动横向滚动的TextView(文字长度不够也可以)
- Android开发心得——点击EditText的时候,输入法把整体布局顶出了屏幕?这里提供一个我个人的解决办法
- android开发游记:RecycleView 实现复杂首页布局三种方式
- android TextView 垂直自动滚动字幕实现TextSwitcher
- 【安卓-自定义布局】安卓App开发思路 一步一个脚印(七)实现ViewPager无限循环与自动播放
- Android TextView实现点击展开动画效果
- android TextView 垂直自动滚动字幕实现
- android开发游记:viewpager关联tabs,自定义tabs实现翻页滚动效果
- 文本内容超过TextView的长度时,实现文本内容水平滚动效果
- android开发游记:RecycleView 实现复杂首页布局三种方式
- Android开发UI之textview实现高亮显示并点击跳转
- android 开发中进入一个activity界面软键盘自动弹出解决(布局中有edittext)
- Android开发之TextView文字水平滚动效果实现
- android TextView 垂直自动滚动字幕实现