自定义可折叠textview

定义相关基本属性

ids.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 原始textview -->
    <item name="id_source_textview" type="id"></item>
    <!-- 收起展开按钮imageview -->
    <item name="id_expand_imageview" type="id"></item>
</resources>
 
 
自定义属性
<declare-styleable name="ExpandableTextViewAttr">
    <!-- 允许显示最大行数 -->
    <attr name="maxExpandLines" format="integer"></attr>
    <!-- 动画执行时间 -->
    <attr name="duration" format="integer"></attr>
</declare-styleable>
自定义Textview
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.leku.diary.R;


public class ExpandableTextView extends RelativeLayout {

    TextView id_source_textview;
    ImageView id_expand_imageview;

    //允许显示最大行数
    int maxExpandLines = 4;
    //动画执行时间
    int duration = 0;

    //是否发生过文字变动
    boolean isChange = false;
    //文本框真实高度
    int realTextViewHeigt = 0;
    //默认不展开
    boolean isExpanded = false;
    //收起时候的整体高度
    int collapsedHeight = 0;
    //剩余点击按钮的高度
    int lastHeight = 0;
    //是否正在执行动画
    boolean isAnimate = false;

    OnExpandStateChangeListener listener;

    public ExpandableTextView(Context context) {
        this(context, null);
    }

    public ExpandableTextView(Context context, AttributeSet attrs) {
        super(context, attrs);

        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ExpandableTextViewAttr);
        maxExpandLines = array.getInteger(R.styleable.ExpandableTextViewAttr_maxExpandLines, 4);
        duration = array.getInteger(R.styleable.ExpandableTextViewAttr_duration, 500);
        array.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        id_source_textview = (TextView) findViewById(R.id.id_source_textview);
        id_expand_imageview = (ImageView) findViewById(R.id.id_expand_imageview);
        id_expand_imageview.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ExpandCollapseAnimation animation;

                isExpanded = !isExpanded;
                if (isExpanded) {
                    id_expand_imageview.setImageDrawable(getResources().getDrawable(R.mipmap.arrow_up));
                    if (listener != null) {
                        listener.onExpandStateChanged(false);
                    }
                    animation = new ExpandCollapseAnimation(getHeight(), realTextViewHeigt + lastHeight);
                } else {
                    id_expand_imageview.setImageDrawable(getResources().getDrawable(R.mipmap.down_arrow));
                    if (listener != null) {
                        listener.onExpandStateChanged(true);
                    }
                    animation = new ExpandCollapseAnimation(getHeight(), collapsedHeight);
                }
                animation.setFillAfter(true);
                animation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                        isAnimate = true;
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        clearAnimation();
                        isAnimate = false;
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });
                clearAnimation();
                startAnimation(animation);
                //不带动画的处理方式
//                isChange=true;
//                requestLayout();
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //执行动画的过程中屏蔽事件
        return isAnimate;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //如果隐藏控件或者textview的值没有发生改变,那么不进行测量
        if (getVisibility() == GONE || !isChange) {
            return;
        }
        isChange = false;

        //初始化默认状态,即正常显示文本
        id_expand_imageview.setVisibility(GONE);
        id_source_textview.setMaxLines(Integer.MAX_VALUE);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        //如果本身没有达到收起展开的限定要求,则不进行处理
        if (id_source_textview.getLineCount() <= maxExpandLines) {
            return;
        }

        //初始化高度赋值,为后续动画事件准备数据
        realTextViewHeigt = getRealTextViewHeight(id_source_textview);

        //如果处于收缩状态,则设置最多显示行数
        if (!isExpanded) {
            id_source_textview.setMaxLines(maxExpandLines);
        }
        id_expand_imageview.setVisibility(VISIBLE);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (!isExpanded) {
            id_source_textview.post(new Runnable() {
                @Override
                public void run() {
                    lastHeight = getHeight() - id_source_textview.getHeight();
                    collapsedHeight = getMeasuredHeight();
                }
            });
        }
    }

    /**
     * 获取textview的真实高度
     *
     * @param textView
     * @return
     */
    private int getRealTextViewHeight(TextView textView) {
        //getLineTop返回值是一个根据行数而形成等差序列,如果参数为行数,则值即为文本的高度
        int textHeight = textView.getLayout().getLineTop(textView.getLineCount());
        return textHeight + textView.getCompoundPaddingBottom() + textView.getCompoundPaddingTop();
    }

    public void setText(String text) {
        isChange = true;
        id_source_textview.setText(text);
    }

    public void setText(String text, boolean isExpanded) {
        this.isExpanded = isExpanded;
        if (isExpanded) {
            id_expand_imageview.setImageDrawable(getResources().getDrawable(R.mipmap.arrow_up));
        } else {
            id_expand_imageview.setImageDrawable(getResources().getDrawable(R.mipmap.down_arrow));
        }
        clearAnimation();
        setText(text);
        getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
    }

    public void setListener(OnExpandStateChangeListener listener) {
        this.listener = listener;
    }

    private class ExpandCollapseAnimation extends Animation {
        int startValue = 0;
        int endValue = 0;

        public ExpandCollapseAnimation(int startValue, int endValue) {
            setDuration(duration);
            this.startValue = startValue;
            this.endValue = endValue;
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            int height = (int) ((endValue - startValue) * interpolatedTime + startValue);
            id_source_textview.setMaxHeight(height - lastHeight);
            ExpandableTextView.this.getLayoutParams().height = height;
            ExpandableTextView.this.requestLayout();
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    }

    public interface OnExpandStateChangeListener {
        void onExpandStateChanged(boolean isExpanded);
    }
}
adapter 调用
topicHolder.expandable_text.setText(mDatas.get(position).content, mDatas.get(position).isExpandable);
topicHolder.expandable_text.setListener(new ExpandableTextView.OnExpandStateChangeListener() {
    @Override
    public void onExpandStateChanged(boolean isExpanded) {
        mDatas.get(position).isExpandable = isExpanded;
    }
});




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值