一个带展开按钮的TextView控件

网上找了很多三方的实现但是都不是我想要的效果或者实现比较复杂,然后就自己写了一个。

就这种效果其实就是很轻量级的一个实现。

首先看我实现的第一个版本。

public class ExpandTextView extends AppCompatTextView {

    /**
     * 的右侧文字Drawable
     */
    private TextDrawable mTextDrawable;

    /**
     * 点击了展开按钮
     */
    private boolean clickExpanded = false;

    /**
     * 允许输入的最大行数
     */
    private volatile int mMaxline = -1;

    public ExpandTextView(Context context) {
        this(context, null);

    }

    public ExpandTextView(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.textViewStyle);
    }

    public ExpandTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mTextDrawable = new TextDrawable(context);
        String str = "「展开」";
        SpannableString spannableString = new SpannableString(str);
        spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#9891FB")), 1, str.length() - 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        mTextDrawable.setText(spannableString);
        mTextDrawable.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
        mTextDrawable.setTextColor(Color.parseColor("#FF282828"));
        mTextDrawable.setTextAlign(Layout.Alignment.ALIGN_CENTER);
        mTextDrawable.setBounds(0, 0, mTextDrawable.getIntrinsicWidth(), mTextDrawable.getIntrinsicHeight());
    }

    @Override
    public void setMaxLines(int maxLines) {
        mMaxline = maxLines;
    }


    private void setTextDrawableVisible(boolean visible) {
        Drawable rightDrawble = visible ? mTextDrawable : null;
        setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], rightDrawble, getCompoundDrawables()[3]);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        super.setText(text, type);
        registerpredrawListener();
    }

    private void registerpredrawListener() {
        RxView.preDraws(this, new Function0<Boolean>() {
            @Override
            public Boolean invoke() {
                return false;
            }
        }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseObserver<Unit>() {
                    @Override
                    public void onNext(Unit bean) {
                        dispose();
                        int lineCouunt = getLineCount();
                        if (lineCouunt > 1) {
                            setGravity(Gravity.LEFT);
                            if (clickExpanded) {
                                //点击过展开按钮就不再显示展开按钮了,直接设置最大行数
                                ExpandTextView.super.setMaxLines(mMaxline < 0 ? Integer.MAX_VALUE : mMaxline);
                                setTextDrawableVisible(false);
                            } else {
                                //没有点击过展开按钮
                                ExpandTextView.super.setMaxLines(1);
                                setTextDrawableVisible(true);
                            }
                        } else {
                            setGravity(Gravity.CENTER);
                            setTextDrawableVisible(false);
                        }
                    }
                });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (getCompoundDrawables()[2] != null) {
                float x = event.getX();
                float padRight = getPaddingRight();
                float iconWidth = getCompoundDrawables()[2].getIntrinsicWidth();
                boolean touchAble = (x > (getWidth() - padRight - iconWidth)) && (x < getWidth() - padRight);

                if (touchAble) {
                    clickExpanded = true;
                    super.setMaxLines(mMaxline < 0 ? Integer.MAX_VALUE : mMaxline);
                    setTextDrawableVisible(false);
                }
            }
        }

        return super.onTouchEvent(event);
    }
}

实现方法很简单,就是在右侧的Drawable中添加一个展开的文本形式的Drawable,然后给它一个点击事件,点击就把Maxlines修改掉。在OnPreDrawListener中获取TextView的lineCount对展开按钮进行显示与隐藏的控制。这么做没有太大的毛病,但是我将其放在了可以滑动的布局中,在展开文本后就有问题了,布局就不能滑动了。因为开展之后测量的布局不准了。为了解决这个问题我写了第二个版本

public class ExpandableTextView extends AppCompatTextView {

    /**
     * 的右侧文字Drawable
     */
    private TextDrawable mTextDrawable;

    /**
     * 点击了展开按钮
     */
    private boolean clickExpanded = false;

    /**
     * 允许输入的最大行数
     */
    private volatile int mMaxline = -1;

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

    }

    public ExpandableTextView(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.textViewStyle);
    }

    public ExpandableTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mTextDrawable = new TextDrawable(context);
        String str = "「展开」";
        SpannableString spannableString = new SpannableString(str);
        spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#9891FB")), 1, str.length() - 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        mTextDrawable.setText(spannableString);
        mTextDrawable.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
        mTextDrawable.setTextColor(Color.parseColor("#FF282828"));
        mTextDrawable.setTextAlign(Layout.Alignment.ALIGN_CENTER);
        mTextDrawable.setBounds(0, 0, mTextDrawable.getIntrinsicWidth(), mTextDrawable.getIntrinsicHeight());
    }

    @Override
    public void setMaxLines(int maxLines) {
        mMaxline = maxLines;
    }


    private void setTextDrawableVisible(boolean visible) {
        Drawable rightDrawble = visible ? mTextDrawable : null;
        setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], rightDrawble, getCompoundDrawables()[3]);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        super.setText(text, type);
        requestLayout();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ExpandableTextView.super.setMaxLines(mMaxline < 0 ? Integer.MAX_VALUE : mMaxline);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int lineCouunt = getLineCount();
        if (lineCouunt > 1) {
            setGravity(Gravity.LEFT);
            if (clickExpanded) {
                //点击过展开按钮就不再显示展开按钮了,直接设置最大行数
                ExpandableTextView.super.setMaxLines(mMaxline < 0 ? Integer.MAX_VALUE : mMaxline);
                setTextDrawableVisible(false);
            } else {
                //没有点击过展开按钮
                ExpandableTextView.super.setMaxLines(1);
                setTextDrawableVisible(true);
            }
        } else {
            setGravity(Gravity.CENTER);
            setTextDrawableVisible(false);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (getCompoundDrawables()[2] != null) {
                float x = event.getX();
                float padRight = getPaddingRight();
                float iconWidth = getCompoundDrawables()[2].getIntrinsicWidth();
                boolean touchAble = (x > (getWidth() - padRight - iconWidth)) && (x < getWidth() - padRight);

                if (touchAble) {
                    clickExpanded = true;
                    requestLayout();

                }
            }
        }

        return super.onTouchEvent(event);
    }
}

在TextView的onMeasure中获取lineCount对展开按钮进行控制,如果TextView已经展开就再进行一次测量。这样展开后的测量数据就是准确的了。

项目GitHub地址:https://github.com/Siy-Wu/PersonalHederZoomIn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值