可折叠展开的TextView
在很多时候需要用到可以折叠、展开的TextView,最常见的就是在各大应用市场描述APP的时候,因为有的描述内容太长了,所以只显示了几行,当点击之后就展开显示了全部内容,再次点击又可以折叠起来。今天我们就从几个不同的角度来实现这种功能,当然越简单的方法效果也就越low了。
通过设置可见与不可见来实现
其实这种方法也最容易想到的,就是在布局的时候就设置两个TextView,其中一个TextView通过
android:maxLines="Integer"
来设置只显示几行,另外一个则按照常规的设置显示全部,只是一开始设置
android:visibility="gone"
那么通过切换这两个TextView的显示与隐藏,就可以达到类似折叠展开的效果了。只是看上去没有任何动画,显得很死板,效果自然不怎么好了。
通过动态改变TextView的高度
其实从另外一个角度来看,这种TextView的折叠与展开就是控件本身高度的一个逐渐变化。
那么一开始就设置一个限制的高度,可能很多人会想通过以下连个个属性来限制TextView的高度
android:maxLines="Integer"
android:maxHeight="Integer"
但是设置了这两个中的任何一个属性之后,再要改变TextView的高度是没有任何效果的。
那么就有人会问了,该怎么设置TextView一开始的高度呢?第一种方法是直接设置TextView的高度,将其设置为一个固定的值,但是在改变了字体大小的时候,那么也要跟着改变这个值,而且不知道设置多少比较合适。第二种方法就是动态获取一个高度:
TextView textView = new TextView(this);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);//设置字体大小14dp
textView.setMaxLines(3);
textView.setLines(3);// 强制有3行
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.AT_MOST);
textView.measure(widthMeasureSpec, heightMeasureSpec);
return textView.getMeasuredHeight();
以上代码,通过创建一个TextView,并给它设置字体大小,以及限制显示的行数,再用measure()方法测量获取到高度。
可能有的人不太理解measure()的使用。在自定义View的时候,经常看见onMeasure()这个方法,可以将其理解为制定测量的规则,而这里使用的measure()算是对控件的实际测量。
在获取到被限制的高度之后,就在一开始初始化控件的时候,给TextView设置上这么一个高度
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) text1.getLayoutParams();
layoutParams.height=value; // 设置初始化时候的高度
text1.setLayoutParams(layoutParams);
随后再获取完整显示时候的高度了。
int width = text1.getMeasuredWidth(); // 由于宽度不会发生变化 宽度的值取出来
text1.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;// 让高度包裹内容
// 参数1 测量控件mode 参数2 大小
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY); // mode+size
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.AT_MOST);// 我的高度 最大是1000
// 测量规则 宽度是一个精确的值width, 高度最大是1000,以实际为准
text1.measure(widthMeasureSpec, heightMeasureSpec); // 通过该方法重新测量控件
return text1.getMeasuredHeight();
在获取完这两个高度的值以后,就可以设置一个动画效果,让高度从小的那个值逐渐增加到大的那个值。这里我们就直接采用值动画了,至于为什么就自己琢磨吧。
ValueAnimator animator=ValueAnimator.ofInt(startHeight,targetHeight);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value=(Integer) animation.getAnimatedValue();
ayoutParams.height=value;
text1.setLayoutParams(layoutParams);
}
});
通过自定义控件
一般在使用可折叠展开的TextView的时候,都会有一个用来指示的小箭头(ImageView)在TextView的下面。那么我们就可以将TextView和ImageView结合起来,通过自定义的LinearLayout来控制。
1、我们将LinearLayout设置为垂直布局,因为使用场景大部分都是垂直的。
setOrientation(LinearLayout.VERTICAL);
2、初始化控件
@Override
protected void onFinishInflate() {
// 初始化TextView并设置点击事件
mTv = (TextView) findViewById(R.id.expandable_text);
mTv.setOnClickListener(this);
// 初始化小箭头,并设置图片和点击事件
mButton = (ImageButton) findViewById(R.id.expand_collapse);
mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable);
mButton.setOnClickListener(this);
}
3、给TextView设置文本内容
4、获取TextView的真正高度
private static int getRealTextViewHeight(@NonNull TextView textView) {
int textHeight = textView.getLayout().getLineTop(textView.getLineCount());
int padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom();
return textHeight + padding;
}
5、重写onMeasure()方法,根据不同的状态给TextView设置不同的高度
6、写onClick()点击事件,点击后播放动画。
由于这种方法是参考一个第三库来的,所以写得很简单,具体的代码可以在此下载
[ExpandableTextView](https://github.com/whyalwaysmea/ExpandableTextView)