TextView实现展开收起的效果

在做Android的过程中,我们经常会遇到TextView显示文本过长的情况,这里我们以开源库ExpandableTextView为例,对其的实现做一讲解:

实现原理描述:expandableTextView继承自LinearLayout(只支持竖直方向),包含TextView和ImageButton两个子view,通过参数 maxCollapsedLines来设置折叠最大的行数,在onMeasure方法中,判断textView的行数,来进行textview折叠和收起状态的设定;另外,收起和展开的效果则针对TextView的高度进行动画。

** 具体使用方法** :

  • 布局:使用ExpandableTextView作为TextView(指定id为expandable_text)和ImageButton(指定id为expand_collapse)的父View.
  • 设值:设定ExpandableText的maxCollapsedLines为折叠的行数。

** 实现细节:**

  • ExpandableTextView是如何确定子view的?
    答:是通过重写ViewGroup一个回调onFinishInflate()方法,来获取对应的子view(TextView跟ImageButton).
  • OnMeasure中执行了哪些操作?
    答:具体是进行根据展开折叠状态的判断,来设定当前textView的行数以及点击事件和imageButton的显示状态。具体代码如下:
@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// If no change, measure and return

if (!mRelayout || getVisibility() == View.GONE) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

return;

}

mRelayout = false;

// Setup with optimistic case

// i.e. Everything fits. No button needed

mButton.setVisibility(View.GONE);

mTv.setMaxLines(Integer.MAX_VALUE);

// Measure

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// If the text fits in collapsed mode, we are done.

if (mTv.getLineCount() <= mMaxCollapsedLines) {

return;

}

// Saves the text height w/ max lines

mTextHeightWithMaxLines = getRealTextViewHeight(mTv);

// Doesn't fit in collapsed mode. Collapse text view as needed. Show

// button.

if (mCollapsed) {

mTv.setMaxLines(mMaxCollapsedLines);

}

mButton.setVisibility(View.VISIBLE);

// Re-measure with new setup

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

if (mCollapsed) {

// Gets the margin between the TextView's bottom and the ViewGroup's bottom

mTv.post(new Runnable() {

@Override

public void run() {

mMarginBetweenTxtAndBottom = getHeight() - mTv.getHeight();

}

});

// Saves the collapsed height of this ViewGroup

mCollapsedHeight = getMeasuredHeight();

}

}
  • 收起展开动画的实现?
    答:这里实现定义了一个扩展收起的动画,主要针对整个View的高度做动画,因为我们已经知道了view折叠之后的高度和扩展之后的高度(可以算出来),然后修改布局就好。
    具体的动画代码如下:
class ExpandCollapseAnimation extends Animation {

private final View mTargetView;

private final int mStartHeight;

private final int mEndHeight;

public ExpandCollapseAnimation(View view, int startHeight, int endHeight) {

mTargetView = view;

mStartHeight = startHeight;

mEndHeight = endHeight;

setDuration(mAnimationDuration);

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

final int newHeight = (int)((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);

mTv.setMaxHeight(newHeight - mMarginBetweenTxtAndBottom);

if (Float.compare(mAnimAlphaStart, 1.0f) != 0) {

applyAlphaAnimation(mTv, mAnimAlphaStart + interpolatedTime * (1.0f - mAnimAlphaStart));

}

mTargetView.getLayoutParams().height = newHeight;

mTargetView.requestLayout();

}

@Override

public void initialize( int width, int height, int parentWidth, int parentHeight ) {

super.initialize(width, height, parentWidth, parentHeight);

}

@Override

public boolean willChangeBounds( ) {

return true;

}

};

动画调用的代码是在view的点击事件回调中:

Animation animation;

if (mCollapsed) {

animation = new ExpandCollapseAnimation(this, getHeight(), mCollapsedHeight);

} else {

animation = new ExpandCollapseAnimation(this, getHeight(), getHeight() +

mTextHeightWithMaxLines - mTv.getHeight());

}

我们这里就会产生一个疑惑,mTextHeightWithMaxLines(文本全部显示对应的textview的高度)是怎么获取到的呢?相应获取的代码如下:

private static int getRealTextViewHeight(@NonNull TextView textView) {

int textHeight = textView.getLayout().getLineTop(textView.getLineCount());

int padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom();

return textHeight + padding;

}

这里有两个主要的方法,getLineCount获取textview的行数,getLineTop获取textview的行高。
至此,我们就可以实现整个expandableTextView的收起展开的效果了。

  • 如何在ListView中确保当前textView的状态?
    我们知道在多列表view中,都要考虑到view重用的问题,若是expandableTextView不能在这种情况下使用的话,那对我们的使用情景就大有限制了。在这里,在调用setText的时候,提供了SparseBooleanArray collapseStatus和int position来记录当前的展开收起状态了。所以,就需要我们在我们的adapter中也使用相同的数据结构了。具体代码如下:
public void setText(@Nullable CharSequence text, @NonNull SparseBooleanArray collapsedStatus, int position) {

mCollapsedStatus = collapsedStatus;

mPosition = position;

boolean isCollapsed = collapsedStatus.get(position, true);

clearAnimation();

mCollapsed = isCollapsed;

mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable);

setText(text);

getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;

requestLayout();

}

最后,我们关于ExpandableTextView的实现原理就讲完了,具体还有疑问的话,可以提出一起讨论。另外,代码的格式没有做缩进,大家多多担待。灰常感谢。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,388评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 女人是逻辑思维的典范 敢爱敢放下 那便是打破了传统的逻辑思维 如果做到没有贪嗔痴便是天国之女 没有天长没有地久 所...
    2b80048c383c阅读 207评论 0 0
  • 开始做第一项任务,画色卡。不像想象的那么简单,一张色卡用了三个小时。初步了解了各种颜色,体会了笔触的感觉。完美的准...
    新世纪_c638阅读 153评论 0 0
  • “道政”授正道,可敬亦可爱 ——李道政老师课堂随记 “白天干活,晚上读书...
    Faith1030阅读 756评论 2 3