Android開源項目 -- 展開收起TextView

一、項目簡介

項目地址:https://github.com/zhangtiansimple/FoldTextView

效果圖: 

 

二、技術選型

本項目採用LinearLayout與TextView實現,根據開發者設置的最大行數,計算高度然後設置給LinearLayout,從而實現文本摺疊的功能。

 

三、具體實現

1.定義子View的佈局

即文字的展示TextView與下方“展開”、“收起”狀態展示的TextView。

<?xml version="1.0" encoding="utf-8"?>
<merge
    xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
        android:id="@id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@id/tv_state"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:padding="8dp"/>
</merge>

2.計算TextView的真實高度

private int getRealTextViewHeight(@NonNull TextView textView) {
        int textHeight = textView.getLayout().getLineTop(textView.getLineCount());
        int padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom();
        return textHeight + padding;
    }

重寫onMeasure

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //如果沒有重新佈局或者此時沒有加入到視圖中 直接默認測量並返回
        if (!isReLayout || getVisibility() == View.GONE) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            return;
        }

        isReLayout = false;

        //如果可以顯示的下 則不需要狀態Tv
        mStateTv.setVisibility(View.GONE);
        mContentTv.setMaxLines(Integer.MAX_VALUE);

        //測量
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        //如果實際行數小於最大摺疊行數
        if (mContentTv.getLineCount() <= mMaxUnfoldLines) {
            return;
        }

        mTextHeightWithMaxLines = getRealTextViewHeight(mContentTv);

        if (isFold) {
            mContentTv.setMaxLines(mMaxUnfoldLines);
        }
        mStateTv.setVisibility(View.VISIBLE);

        //重新測量
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (isFold) {
            mContentTv.post(mRunnable);
            mUnfoldHeight = getMeasuredHeight();
        }
    }

3.自定義屬性

<declare-styleable name="FoldTextView">
        <attr name="maxUnfoldLines" format="integer"/>
        <attr name="animDuration" format="integer"/>
        <attr name="contentTextSize" format="dimension"/>
        <attr name="contentTextColor" format="color"/>
        <attr name="contentLineSpaceMultiplier" format="float"/>
        <attr name="unFoldDrawable" format="reference"/>
        <attr name="unFoldText" format="string"/>
        <attr name="foldDrawable" format="reference"/>
        <attr name="foldText" format="string"/>
        <attr name="stateTextColor" format="color"/>
        <attr name="stateTvGravity">
            <enum name="left" value="0"/>
            <enum name="center" value="1"/>
            <enum name="right" value="2"/>
        </attr>
    </declare-styleable>

4.設置展開收起的動畫

public class FoldAnimation extends Animation {

    private final View mTargetView;
    private final int mStartHeight;
    private final int mEndHeight;

    private TextView mContentTv;
    private int mMarginBetweenTxtAndBottom;

    public FoldAnimation(View view, int startHeight, int endHeight, TextView contentTv, int animationDuration, int marginBetweenTxtAndBottom) {
        mTargetView = view;
        mStartHeight = startHeight;
        mEndHeight = endHeight;
        mContentTv = contentTv;
        mMarginBetweenTxtAndBottom = marginBetweenTxtAndBottom;
        setDuration(animationDuration);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final int newHeight = (int) ((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);
        mContentTv.setMaxHeight(newHeight - mMarginBetweenTxtAndBottom);
        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;
    }
}

四、總結

以上就是這個工程裏的比較核心的代碼,其他的一些基礎代碼可以在github源碼裏進行查看。

最後灰常感謝看到這裏的小夥伴,相信看到這裏的小夥伴應該對這個項目還是比較感興趣的,如果這個項目中有一些思路或者代碼幫助到了小夥伴,還請給個小小的star作爲鼓勵~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章