Android多行文本折叠展开效果
转自:http://blog.csdn.net/qiaoidea/article/details/45568653
【导航】
- 单行文本水平触摸滑动效果 通过EditText实现TextView单行长文本水平滑动效果
- 多行文本折叠展开 自定义布局View实现多行文本折叠和展开
1.概述
经常在APP中能看到有引用文章或大段博文的内容,他们的展示样式也有点儿意思,默认是折叠的,当你点击文章之后它会自动展开。再次点击他又会缩回去。
网上有找到部分效果,感觉不是很满意。最后自己尝试用 自定义布局layout 写了个demo。比较简陋,不过可以用了。有这方面需求的朋友可以稍加改造下。如有更好的创意,也不妨分享一下。
效果图:
2.具体实现
但从实现效果方面来看,只用简单定义必要view即可,后变为了方便扩展使用和挪用,又对整个布局进行封装,方便直接使用。
2.1 通过多个布局组合实现
第一想法当然是用多个View组合来实现。那么久定义一个LinearLayout布局分别嵌套TextView和ImageView来做。
大概步骤:
- 定义布局,垂直的线性LinearLayout布局、TextView和ImageView。 在layout中定义基本组件。
- 设置TextView的高度为指定行数*行高。 不使用maxLine的原因是maxLine会控制显示文本的行数,不方便后边使用动画展开全部内容。因此这里TextView的高度也因该为wrap_content。
- 给整个布局添加点击事件,绑定动画。 点击时,若TextView未展开则展开至其实际高度,imageView 旋转;否则回缩至 指定行数*行高 , imageView 旋转缩回。
开始编写代码:
1.在xml中定义布局:
<LinearLayoutandroid:id="@+id/description_layout"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:paddingLeft="12dip"android:paddingRight="12dip"android:paddingTop="5dip" ><TextViewandroid:id="@+id/description_view"android:layout_width="match_parent"android:layout_height="wrap_content"android:textColor="@android:color/black"android:textSize="18dip" ></TextView><ImageViewandroid:id="@+id/expand_view"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="right"android:paddingBottom="5dip"android:paddingLeft="5dip"android:paddingRight="5dip"android:paddingTop="5dip"android:src="@drawable/text_ic_expand"android:visibility="gone" /></LinearLayout>
2.首先在activity中定义并初始化这些view:
public class MainActivity extends Activity {TextView descriptionView;View layoutView ,expandView; //LinearLayout布局和ImageViewint maxDescripLine = 3; //TextView默认最大展示行数//在OnCreate中初始化{layoutView = findViewById(R.id.description_layout);descriptionView = (TextView)findViewById(R.id.description_view);expandView = findViewById(R.id.expand_view);}
}
3.然后设置textview显示文本,再根据默认展示行数设置其高度,并根据其是否已完全显示(当前展示行数是否大于等于实际行数)来判断需不需要点击更多按钮。
//设置文本descriptionView.setText(getText(R.string.content));//descriptionView设置默认显示高度descriptionView.setHeight(descriptionView.getLineHeight() * maxDescripLine);//根据高度来判断是否需要再点击展开descriptionView.post(new Runnable() {@Overridepublic void run() {expandView.setVisibility(descriptionView.getLineCount() > maxDescripLine ? View.VISIBLE : View.GONE);}});
因为textView设置的是wrap_content,所以会显示实际高度和行数,这里根据maxDescripLine来设置其高度。
看了最后一行代码可能有人会问?ImageView (点击展开更多)是否应该显示 的判断逻辑为什么要放在post方法里边呢? 这是由于在OnCreate方法中定义设置的textView不会马上渲染并显示,所以textview的getLineCount()获取到的值一般都为零,因此使用post会在其绘制完成后来对ImageView进行显示控制。
ps: 感觉我描述不清的朋友可以看下stackoverflow 上的讲解 how to use getlinecount() in textview android.
4.给layoutView设置点击事件。
给ImageView定义一个RotateAnimation的旋转动画,在旋转过程中根据旋转百分比进度控制textView高度,进而达到我们想要的效果。
layoutView.setOnClickListener(new View.OnClickListener() {boolean isExpand;//是否已展开的状态@Overridepublic void onClick(View v) {isExpand = !isExpand;descriptionView.clearAnimation();//清楚动画效果final int deltaValue;//默认高度,即前边由maxLine确定的高度final int startValue = descriptionView.getHeight();//起始高度int durationMillis = 350;//动画持续时间if (isExpand) {/*** 折叠动画* 从实际高度缩回起始高度*/deltaValue = descriptionView.getLineHeight() * descriptionView.getLineCount() - startValue;RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animation.setDuration(durationMillis);animation.setFillAfter(true);expandView.startAnimation(animation);} else {/*** 展开动画* 从起始高度增长至实际高度*/deltaValue = descriptionView.getLineHeight() * maxDescripLine - startValue;RotateAnimation animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animation.setDuration(durationMillis);animation.setFillAfter(true);expandView.startAnimation(animation);}Animation animation = new Animation() {protected void applyTransformation(float interpolatedTime, Transformation t) { //根据ImageView旋转动画的百分比来显示textview高度,达到动画效果descriptionView.setHeight((int) (startValue + deltaValue * interpolatedTime));}};animation.setDuration(durationMillis);descriptionView.startAnimation(animation);}});
至此,通过布局已经实现了我们想要的效果。具体代码参见代码示例 的第一部分。
当然,我们可以这样使用,但是每次都这么重写未免显得有些麻烦。因此有必要把他写成一个单独控件,方便我们以后的开袋即食。废话不多说,上菜。
2.2 通过自定义View组合封装
这个view的布局结构并不打算使用xml来定义layout,直接定义一个继承LinearLayout的MoreTextView类.这个类里边添加TextView和ImageView。
1.使用styleable自定义View属性
为了后边能够方便的在xml布局中使用MoreTextView这个自定义View,类似通过
android:text = “XXX”
android:textSize = “XXX”
这样快捷的绑定文本内容和设置字体大小等属性,我们可以通过 declare-styleable在values文件下的xml中自定义我们想要的属性,并在View中获取和使用。详细使用declare-styleable的内容会在后边补充,这里简要说下。
比如,MoreTextView应该有的基本属性,像 文本字体大小(textSize)、颜色(textColor)和文本内容(text),还有默认显示行数(maxLine)等几种属性。我们要想像TextView一样直接在xml中设置绑定,可以这样做。
首先在values目录下新建个attrs.xml(名字随意),并定义MoreTextView这些属性。
<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="MoreTextStyle"><attr name="textSize" format="dimension"/><attr name="textColor" format="color"/><attr name="maxLine" format="integer" /><attr name="text" format="string" /></declare-styleable>
</resources>
2.自定义MoreTextView并获取这些属性的值
上边定义了这些属性,就等于允许我们在xml中使用
more:text = “XXX”
more:textSize = “XXX”
more : textColor = “XXX”
more : maxLine = “XXX”
(注: more这个关键字可以随意)
这样直接设置属性值。那么具体怎么取值,我们稍后来讲。
(1)定义MoreTextView的属性:
public class MoreTextView extends LinearLayout{protected TextView contentView; //文本正文protected ImageView expandView; //展开按钮//对应styleable中的属性protected int textColor; protected float textSize;protected int maxLine;protected String text;//默认属性值public int defaultTextColor = Color.BLACK;public int defaultTextSize = 12;public int defaultLine = 3;//....实现部分略
}
(2)MoreTextView的构造方法:
public MoreTextView(Context context, AttributeSet attrs) {super(context, attrs);initalize(); initWithAttrs(context, attrs); bindListener();}
这三个方法简单说明下:
- initalize() 初始化并添加View。初始化TextView和ImageView,并添加到MoretextView中去。
- initWithAttrs(context, attrs) 取值并设置。利用attrs从xml布局中取我们配置好的text/textSize/textColor/maxLine等属性的属性值,并设置到View上去。
- bindListener() 绑定点击事件并设置动画。 给当前MoreTextView设置点击事件,实现点击折叠和展开。
各个方法的具体实现:
//初始化并添加View
protected void initalize() {setOrientation(VERTICAL); //设置垂直布局setGravity(Gravity.RIGHT); //右对齐//初始化textView并添加contentView = new TextView(getContext());addView(contentView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);//初始化ImageView并添加expandView = new ImageView(getContext());int padding = dip2px(getContext(), 5);expandView.setPadding(padding, padding, padding, padding);expandView.setImageResource(R.drawable.text_ic_expand);LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);addView(expandView, llp);
取值并设置这部分有必要将一下。我们利用TypedArray从定义的styleable中取出属性值,赋给我们定义好的类的属性变量。记得取完之后调用recycle()回收释放。
protected void initWithAttrs(Context context, AttributeSet attrs) {TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MoreTextStyle); int textColor = a.getColor(R.styleable.MoreTextStyle_textColor, defaultTextColor); //取颜色值,默认defaultTextColortextSize = a.getDimensionPixelSize(R.styleable.MoreTextStyle_textSize, defaultTextSize);//取颜字体大小,默认defaultTextSizemaxLine = a.getInt(R.styleable.MoreTextStyle_maxLine, defaultLine);//取颜显示行数,默认defaultLinetext = a.getString(R.styleable.MoreTextStyle_text);//取文本内容//绑定到textView bindTextView(textColor,textSize,maxLine,text);a.recycle();//回收释放}//绑定到textView protected void bindTextView(int color,float size,final int line,String text){contentView.setTextColor(color);contentView.setTextSize(TypedValue.COMPLEX_UNIT_PX,size);contentView.setText(text);contentView.setHeight(contentView.getLineHeight() * line);post(new Runnable() {//前面已讲,不再赘述@Overridepublic void run() {expandView.setVisibility(contentView.getLineCount() > line ? View.VISIBLE : View.GONE);}});}
最后设置点击事件。
//点击展开与折叠,不再赘述protected void bindListener(){setOnClickListener(new View.OnClickListener() {boolean isExpand;@Overridepublic void onClick(View v) {isExpand = !isExpand;contentView.clearAnimation();final int deltaValue;final int startValue = contentView.getHeight();int durationMillis = 350;if (isExpand) {deltaValue = contentView.getLineHeight() * contentView.getLineCount() - startValue;RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animation.setDuration(durationMillis);animation.setFillAfter(true);expandView.startAnimation(animation);} else {deltaValue = contentView.getLineHeight() * maxLine - startValue;RotateAnimation animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animation.setDuration(durationMillis);animation.setFillAfter(true);expandView.startAnimation(animation);}Animation animation = new Animation() {protected void applyTransformation(float interpolatedTime, Transformation t) {contentView.setHeight((int) (startValue + deltaValue * interpolatedTime));}};animation.setDuration(durationMillis);contentView.startAnimation(animation);}});}
另外,定义几个方法方便外部调用(获取文本TextView,直接设置文本内容),同时还定义了一个dip转像素的静态方法。
public TextView getTextView(){return contentView;}public void setText(CharSequence charSequence){contentView.setText(charSequence);}public static int dip2px(Context context, float dipValue){ final float scale = context.getResources().getDisplayMetrics().density; return (int)(dipValue * scale + 0.5f); }
其实到这里,我们的自定义多文本折叠展开MoreTextView已经完成了。如何使用呢?
在layout/xx.xml中使用
要想方便的使用我们刚刚的自定义属性来定义值,记得在xml namespace中定义应用:自动引用命名空间res-auto
xmlns:more=”http://schemas.android.com/apk/res-auto”
或者 直接定义包名
xmlns:more=”http://schemas.android.com/apk/res/com.qiao.moretext”命名空间后边跟的 more即下边你要使用自定义属性的开头部分。
比如我们的activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:more="http://schemas.android.com/apk/res/com.qiao.moretext"android:id="@+id/root"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/white"android:orientation="vertical" ><com.qiao.moretext.MoreTextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dip" more:textColor="@android:color/black"more:textSize="18dip"more:maxLine="3"more:text="@string/content"/></LinearLayout>
- 在java中直接定义使用
由于上边定义MoreTextView只定义了一种构造方法 MoreTextView(Context context, AttributeSet attrs) ,所以使用时,也只能:
MoreTextView content = new MoreTextView(MainActivity.this, null);content.setText(getText(R.string.content));//然后addview到你要添加的地方
当然,聪明如你,可肯定知道怎么定义另外的构造方法来简单实用啦。
–>
MoreTextView(Context context){
//使用默认值直接初始化
bindTextView();
}
3.综述
综上呢,我们已经完成了所要实现的功能,作为UI呢,他可能会有些简陋,但作为一个demo起到示范作用已经够了。后边我们可能会考虑把它作为微博的一个listitem做成列表一样,并加入点赞等功能。有兴趣不妨做一下咯。。
源码示例下载地址
Android多行文本折叠展开效果相关推荐
- 小程序多行文本折叠展开
小程序多行文本折叠&展开 1 通过样式控制显示的行数 2 通过代码逻辑控制显示的字数 1 通过样式控制显示的行数 js代码: data: {news: "据国家卫生健康委发布,2月2 ...
- android自定义伸缩框(展开效果)
</pre>在android中往往在很多时候用到伸缩框也就是展开效果,或者说是折叠效果,当然在Android中系统也有个类似QQ好友的方式的View "ExpandableLis ...
- CSS和JS实现内容折叠/展开效果
经常逛 CSDN 的朋友会发现如下效果:当代码行数超过指定高度的时候,会有折叠,点击展开按钮后才会展示全部. 这一效果在知乎.百度知道也很常见. 实现 直接上代码 <!DOCTYPE html& ...
- 微信小程序 - 折叠展开效果
wxml: <view class="page"> <!-- 总数 --> <view class="li" bindtap='c ...
- Bootstrap多个手风琴折叠展开效果
Bootstrap多个手风琴点击的效果: <!DOCTYPE html> <html><head><meta charset="utf-8" ...
- 左侧菜单栏左滑收起展开效果
上一篇文章 左侧菜单栏折叠展开效果-超级简单介绍了将菜单列表上下展开的效果,这里在上一篇文章的基础上增加了左右折叠展开,有时候左侧菜单可能占了屏幕的一部分宽度,我们想把左侧菜单栏收缩起来以此让右边可视 ...
- element-ui之el-collapse-transition(折叠展开动画)源码解析学习
2019独角兽企业重金招聘Python工程师标准>>> 项目中发现同事使用了element-ui的el-collapse-transition来做折叠展开效果,打开源码看了下发现挺有 ...
- android 折叠式布局,Android卡片式折叠交互效果
原标题:Android卡片式折叠交互效果 近日有报道称:在互联网共享单车最早起步的上海,目前有150万辆共享单车.迅猛的增速之下,上海市交通委紧急叫停,成为继杭州.广州等城市之后,国内又一个暂停新增投 ...
- android可折叠窗口,Android Studio使用recyclerview实现展开和折叠功能(在之前的微信页面基础之上)...
Android中RecyclerView点击item展开列表详细内容 效果如下: 依然是xml文件的设计,使用了两个RelativeLayout,zu作为主布局和副布局,里面都加入textview显示 ...
最新文章
- 计算机考研b区国家线,考研b区国家线历年分数线情况
- 大型网站架构系列:电商网站架构案例(2)
- python文件io是啥意思_Python文件IO(普通文件读写)
- 2021年春季学期-信号与系统-第十次作业参考答案-第四小题
- Linux中的popen-pclose
- SuperMap注册流程记录
- 人工智能大脑如何调控智能交通“疏堵”?
- 【es】将 elasticsearch 写入速度优化到极限
- 用这4种策略提高你的Facebook广告浏览量
- 我是一个尝试做自媒体的程序员
- 「leetcode」78. 子集【回溯算法】详解!
- python蓝牙模块_Python蓝牙模块lightblue在mac osx 10.8上不起作用
- 2021-2027全球与中国创建和销售在线课程平台市场现状及未来发展趋势
- jquery form表单提交
- 指派问题java实现_指派问题及实现代码示例.ppt
- pano2vr无法输出html5,教大家Pano2VR怎么输出全景图的方法
- python求平均数直到0出现while_Python第一周 学习笔记(2)
- adblock plus去广告插件下载与安装
- uni-app以h5网页的方式发布企业微信应用
- OpenGL着色器透视变换实例-通过旋转平移调试着色器
热门文章
- 一个开源的论坛系统AstalPathTalk
- 理解——先序遍历是入栈过程,中序遍历是出栈过程
- 基于JAVA幼儿健康管理系统计算机毕业设计源码+系统+数据库+lw文档+部署
- BC1.2和QC2.0充电器识别过程
- fig翻译_Fig. 2. (a) Loading equipment; (b) Distributi简体中文怎么写 - 什么意思? - 怎么翻译?...
- 中等专业学校校园广播系统解决方案,职业中专校园IP网络广播系统建设设计指南,校园IP网络广播在职业院校的应用分析
- MULLS: Versatile LiDAR SLAM via Multi-metric Linear Least Square 论文翻译
- 中级工程师如何走向高级
- 天大18年6月考试财务报表分析4
- NS3 sixth.cc注释