Android TextView實(shí)現(xiàn)多文本折疊、展開效果
背景
在開發(fā)過程中,當(dāng)我們的需求中包含說說或者評論等內(nèi)容的展示時,我們都會考慮當(dāng)內(nèi)容太多時該如何顯示。當(dāng)內(nèi)容的字?jǐn)?shù)太多,如果全部展示出來可能會影響體驗(yàn)效果,但是又不能只截取一部分內(nèi)容進(jìn)行展示,此時就需要考慮使用多行顯示折疊的效果來實(shí)現(xiàn)。
效果圖:

使用
1.布局文件調(diào)用
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.wiggins.expandable.widget.MoreLineTextView android:id="@+id/tv_more_line_short" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:padding="@dimen/padding_small" app:clickAll="true" app:textColor="@color/red" /> <View style="@style/spaceLine" /> <com.wiggins.expandable.widget.expandable.ExpandableTextView android:id="@+id/tv_expandable_short" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:ellipsize="end" android:padding="@dimen/padding_small" android:textColor="@color/blue" app:allClickable="false" app:contentTextColor="@color/blue" app:isDisplayIcon="false" app:maxCollapsedLines="4" /> <View style="@style/spaceLine" /> <com.wiggins.expandable.widget.MoreLineTextView android:id="@+id/tv_more_line_long" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:padding="@dimen/padding_small" app:clickAll="true" app:textColor="@color/red" /> <View style="@style/spaceLine" /> <com.wiggins.expandable.widget.expandable.ExpandableTextView android:id="@+id/tv_expandable_long" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:ellipsize="end" android:padding="@dimen/padding_small" android:textColor="@color/blue" app:allClickable="false" app:contentTextColor="@color/blue" app:isDisplayIcon="false" app:maxCollapsedLines="4" /> </LinearLayout>
2.Java文件調(diào)用
private void initData() {
mTvMoreLineShort.setText(Constant.content1);
mTvExpandableShort.setText(Constant.content2);
mTvMoreLineLong.setText(Constant.content3);
mTvExpandableLong.setText(Constant.content4);
}
MoreLineTextView使用
1.在attr.xml中定義屬性
<declare-styleable name="MoreTextStyle"> <!--內(nèi)容大小--> <attr name="textSize" format="dimension" /> <!--內(nèi)容顏色--> <attr name="textColor" format="color" /> <!--內(nèi)容默認(rèn)最大行數(shù)--> <attr name="maxLine" format="integer" /> <!--展開/收起圖標(biāo)--> <attr name="expandIcon" format="reference" /> <!--展開/收起動畫執(zhí)行時間--> <attr name="durationMillis" format="integer" /> <!--可點(diǎn)擊區(qū)域,默認(rèn)展開/收起區(qū)域可點(diǎn)擊--> <attr name="clickAll" format="boolean" /> </declare-styleable>
2.是否顯示折疊效果
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 如果沒有變化,測量并返回
if (!mRelayout || getVisibility() == View.GONE) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
mRelayout = false;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 內(nèi)容區(qū)域初始顯示行高
mTvContent.setHeight(mTvContent.getLineHeight() * (mMaxLine > mTvContent.getLineCount() ? mTvContent.getLineCount() : mMaxLine));
mLlExpand.post(new Runnable() {
@Override
public void run() {
// 是否顯示折疊效果
mLlExpand.setVisibility(mTvContent.getLineCount() > mMaxLine ? View.VISIBLE : View.GONE);
}
});
}
3.設(shè)置顯示內(nèi)容
/**
* @Description 設(shè)置顯示內(nèi)容
*/
public void setText(String str) {
mRelayout = true;
mTvContent.setText(str);
setVisibility(TextUtils.isEmpty(str) ? View.GONE : View.VISIBLE);
}
4.展開/收起動畫
@Override
public void onClick(View v) {
if (mTvContent.getLineCount() <= mMaxLine) {
return;
}
isExpand = !isExpand;
mTvContent.clearAnimation();
final int deltaValue;
final int startValue = mTvContent.getHeight();
if (isExpand) {
deltaValue = mTvContent.getLineHeight() * mTvContent.getLineCount() - startValue;//計(jì)算要展開高度
RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(mDurationMillis);
animation.setFillAfter(true);
mIvExpand.startAnimation(animation);
mTvExpand.setText(getContext().getString(R.string.collapse));
} else {
deltaValue = mTvContent.getLineHeight() * mMaxLine - startValue;//為負(fù)值,收縮的高度
RotateAnimation animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(mDurationMillis);
animation.setFillAfter(true);
mIvExpand.startAnimation(animation);
mTvExpand.setText(getContext().getString(R.string.expand));
}
Animation animation = new Animation() {
protected void applyTransformation(float interpolatedTime, Transformation t) {
//interpolatedTime:為當(dāng)前動畫幀對應(yīng)的相對時間,值總在0-1之間,原始長度+高度差*(從0到1的漸變)即表現(xiàn)為動畫效果
mTvContent.setHeight((int) (startValue + deltaValue * interpolatedTime));
}
};
animation.setDuration(mDurationMillis);
mTvContent.startAnimation(animation);
}
ExpandableTextView使用
1.在attr.xml中定義屬性
<declare-styleable name="ExpandableTextView"> <!--內(nèi)容默認(rèn)最大行數(shù),超過隱藏--> <attr name="maxCollapsedLines" format="integer" /> <!--展開/收起動畫執(zhí)行時間--> <attr name="animDuration" format="integer" /> <!--展開圖片--> <attr name="expandDrawable" format="reference" /> <!--收起圖片--> <attr name="collapseDrawable" format="reference" /> <!--內(nèi)容顏色--> <attr name="contentTextColor" format="color" /> <!--內(nèi)容大小--> <attr name="contentTextSize" format="dimension" /> <!--收起/展開顏色--> <attr name="collapseExpandTextColor" format="color" /> <!--收起/展開大小--> <attr name="collapseExpandTextSize" format="dimension" /> <!--收起文字--> <attr name="textCollapse" format="string" /> <!--展開文字--> <attr name="textExpand" format="string" /> <!--可點(diǎn)擊區(qū)域,默認(rèn)展開/收起區(qū)域可點(diǎn)擊--> <attr name="allClickable" format="boolean" /> <!--是否顯示展開/收起圖標(biāo),默認(rèn)顯示--> <attr name="isDisplayIcon" format="boolean" /> <!--收起/展開位置,默認(rèn)左邊--> <attr name="collapseExpandGrarity"> <flag name="left" value="3" /> <flag name="right" value="5" /> </attr> <!--收起/展開圖標(biāo)位置,默認(rèn)右邊--> <attr name="drawableGrarity"> <flag name="left" value="3" /> <flag name="right" value="5" /> </attr> </declare-styleable>
2.是否顯示折疊效果
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 如果沒有變化,測量并返回
if (!mRelayout || getVisibility() == View.GONE) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
mRelayout = false;
// Setup with optimistic case
// i.e. Everything fits. No button needed
mLlExpand.setVisibility(View.GONE);
mTvContent.setMaxLines(Integer.MAX_VALUE);
// Measure
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//如果內(nèi)容真實(shí)行數(shù)小于等于最大行數(shù),不處理
if (mTvContent.getLineCount() <= mMaxCollapsedLines) {
return;
}
// 獲取內(nèi)容tv真實(shí)高度(含padding)
mTextHeightWithMaxLines = getRealTextViewHeight(mTvContent);
// 如果是收起狀態(tài),重新設(shè)置最大行數(shù)
if (mCollapsed) {
mTvContent.setMaxLines(mMaxCollapsedLines);
}
mLlExpand.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
mTvContent.post(new Runnable() {
@Override
public void run() {
mMarginBetweenTxtAndBottom = getHeight() - mTvContent.getHeight();
}
});
// 保存這個容器的測量高度
mCollapsedHeight = getMeasuredHeight();
}
}
3.設(shè)置顯示內(nèi)容
/**
* @Description 設(shè)置顯示內(nèi)容
*/
public void setText(CharSequence text) {
mRelayout = true;
mTvContent.setText(text);
setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);
}
4.展開/收起動畫
@Override
public void onClick(View view) {
if (mLlExpand.getVisibility() != View.VISIBLE) {
return;
}
mCollapsed = !mCollapsed;
// 修改收起/展開圖標(biāo)、文字
setDrawbleAndText();
// 保存位置狀態(tài)
if (mCollapsedStatus != null) {
mCollapsedStatus.put(mPosition, mCollapsed);
}
// 執(zhí)行展開/收起動畫
mAnimating = true;
ValueAnimator valueAnimator;
if (mCollapsed) {
valueAnimator = new ValueAnimator().ofInt(getHeight(), mCollapsedHeight);
} else {
mCollapsedHeight = getHeight();
valueAnimator = new ValueAnimator().ofInt(getHeight(), getHeight() + mTextHeightWithMaxLines - mTvContent.getHeight());
}
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int animatedValue = (int) valueAnimator.getAnimatedValue();
mTvContent.setMaxHeight(animatedValue - mMarginBetweenTxtAndBottom);
getLayoutParams().height = animatedValue;
requestLayout();
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
// 動畫結(jié)束后發(fā)送結(jié)束的信號,清除動畫標(biāo)志
mAnimating = false;
// 通知監(jiān)聽
if (mListener != null) {
mListener.onExpandStateChanged(mTvContent, !mCollapsed);
}
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
valueAnimator.setDuration(mAnimationDuration);
valueAnimator.start();
}
項(xiàng)目地址 ☞ 傳送門
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android UI實(shí)現(xiàn)多行文本折疊展開效果
- Android TextView多文本折疊展開效果
- Android中RecyclerView實(shí)現(xiàn)多級折疊列表效果(二)
- Android中RecyclerView實(shí)現(xiàn)多級折疊列表效果(TreeRecyclerView)
- Android折疊式Toolbar使用完全解析(CollapsingToolbarLayout)
- android給RecyclerView加上折疊的效果示例
- Android中FoldingLayout折疊布局的用法及實(shí)戰(zhàn)全攻略
- Android TextView仿微信可折疊效果
- Android顯示全文折疊控件使用方法詳解
- Android開發(fā)實(shí)現(xiàn)的文本折疊點(diǎn)擊展開功能示例
相關(guān)文章
android利用消息機(jī)制獲取網(wǎng)絡(luò)圖片
這篇文章主要為大家詳細(xì)介紹了android利用消息機(jī)制獲取網(wǎng)絡(luò)圖片的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
Android自定義LocationMarker的實(shí)現(xiàn)詳解
這篇文章主要為大家詳細(xì)介紹一個比較簡單的東西:自定義繪制Marker 其實(shí)就是自定義view, 跟軌跡沒太多關(guān)聯(lián),感興趣的小伙伴可以跟隨小編一起了解一下2023-02-02
Android 中 ActivityLifecycleCallbacks的實(shí)例詳解
這篇文章主要介紹了Android 中 ActivityLifecycleCallbacks的實(shí)例詳解的相關(guān)資料,希望通過本文大家能掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09
Android實(shí)現(xiàn)app分享文件到微信功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)app分享文件到微信功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-05-05
Android Studio中Run按鈕是灰色的快速解決方法
這篇文章主要介紹了Android Studio中Run按鈕是灰色的快速解決方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-03-03
總結(jié)Android中多線程更新應(yīng)用的頁面信息的方式
這篇文章主要介紹了總結(jié)Android中多線程更新應(yīng)用的頁面信息的方式,文中共總結(jié)了runOnUiThread、Handler、AsyncTask異步以及View直接在UI線程中更新的方法,需要的朋友可以參考下2016-02-02

