android-ExpandTextView

1.

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.text.Layout;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.method.LinkMovementMethod;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;



/**
 * 自定义控件,长文本展开收起TextView
 */

@SuppressLint("AppCompatCustomView")
public class ExpandTextView extends TextView {
    private String originText;// 原始内容文本
    private int initWidth = 0;// TextView可展示宽度
    private int mMaxLines = 3;// TextView最大行数
    private SpannableString SPAN_CLOSE = null;// 收起的文案(颜色处理)
    private SpannableString SPAN_EXPAND = null;// 展开的文案(颜色处理)
    private String TEXT_EXPAND = "  全部";
    private String TEXT_CLOSE = "  收起";

    public ExpandTextView(Context context) {
        super(context);
        initCloseEnd();
    }

    public ExpandTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initCloseEnd();
    }

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

    /**
     * 设置TextView可显示的最大行数
     *
     * @param maxLines 最大行数
     */
    @Override
    public void setMaxLines(int maxLines) {
        this.mMaxLines = maxLines;
        super.setMaxLines(maxLines);
    }

    /**
     * 初始化TextView的可展示宽度
     *
     * @param width
     */
    public void initWidth(int width) {
        initWidth = width;
    }

    /**
     * 收起的文案(颜色处理)初始化
     */
    private void initCloseEnd() {
        String content = TEXT_EXPAND;
        SPAN_CLOSE = new SpannableString(content);
        ButtonSpan span = new ButtonSpan(getContext(), new OnClickListener() {
            @Override
            public void onClick(View v) {
                ExpandTextView.super.setMaxLines(Integer.MAX_VALUE);
                setExpandText(originText);
            }
        }, R.color.colorAccent);
        SPAN_CLOSE.setSpan(span, 0, content.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
    }

    /**
     * 展开的文案(颜色处理)初始化
     */
    private void initExpandEnd() {
        String content = TEXT_CLOSE;
        SPAN_EXPAND = new SpannableString(content);
        ButtonSpan span = new ButtonSpan(getContext(), new OnClickListener() {
            @Override
            public void onClick(View v) {
                ExpandTextView.super.setMaxLines(mMaxLines);
                setCloseText(originText);
            }
        }, R.color.colorAccent);
        SPAN_EXPAND.setSpan(span, 0, content.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
    }

    public void setCloseText(CharSequence text) {

        if (SPAN_CLOSE == null) {
            initCloseEnd();
        }
        boolean appendShowAll = false;// true 不需要展开收起功能, false 需要展开收起功能
        originText = text.toString();

        // SDK >= 16 可以直接从xml属性获取最大行数
        int maxLines = 0;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            maxLines = getMaxLines();
        } else {
            maxLines = mMaxLines;
        }
        String workingText = new StringBuilder(originText).toString();
        if (maxLines != -1) {
            Layout layout = createWorkingLayout(workingText);
            if (layout.getLineCount() > maxLines) {
                //获取一行显示字符个数,然后截取字符串数
                // 收起状态原始文本截取展示的部分
                workingText = originText.substring(0, layout.getLineEnd(maxLines - 1)).trim();
                String showText = originText.substring(0, layout.getLineEnd(maxLines - 1)).trim() + "..." + SPAN_CLOSE;
                Layout layout2 = createWorkingLayout(showText);
                // 对workingText进行-1截取,直到展示行数==最大行数,并且添加 SPAN_CLOSE 后刚好占满最后一行
                while (layout2.getLineCount() > maxLines) {
                    int lastSpace = workingText.length() - 1;
                    if (lastSpace == -1) {
                        break;
                    }
                    workingText = workingText.substring(0, lastSpace);
                    layout2 = createWorkingLayout(workingText + "..." + SPAN_CLOSE);
                }
                appendShowAll = true;
                workingText = workingText + "...";
            }
        }

        setText(workingText);
        if (appendShowAll) {
            // 必须使用append,不能在上面使用+连接,否则spannable会无效
            append(SPAN_CLOSE);
            setMovementMethod(LinkMovementMethod.getInstance());
        }
    }

    public void setExpandText(String text) {
        if (SPAN_EXPAND == null) {
            initExpandEnd();
        }
        Layout layout1 = createWorkingLayout(text);
        Layout layout2 = createWorkingLayout(text + TEXT_CLOSE);
        // 展示全部原始内容时 如果 TEXT_CLOSE 需要换行才能显示完整,则直接将TEXT_CLOSE展示在下一行
        if (layout2.getLineCount() > layout1.getLineCount()) {
            setText(originText + "\n");
        } else {
            setText(originText);
        }
        append(SPAN_EXPAND);
        setMovementMethod(LinkMovementMethod.getInstance());
    }

    //返回textview的显示区域的layout,该textview的layout并不会显示出来,只是用其宽度来比较要显示的文字是否过长
    private Layout createWorkingLayout(String workingText) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            return new StaticLayout(workingText, getPaint(), initWidth - getPaddingLeft() - getPaddingRight(),
                    Layout.Alignment.ALIGN_NORMAL, getLineSpacingMultiplier(), getLineSpacingExtra(), false);
        } else {
            return new StaticLayout(workingText, getPaint(), initWidth - getPaddingLeft() - getPaddingRight(),
                    Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
        }
    }
}

2.

import android.content.Context;
import android.content.res.Resources;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.view.View;


public class ButtonSpan extends ClickableSpan {

    View.OnClickListener onClickListener;
    private Context context;
    private int colorId;

    public ButtonSpan(Context context, View.OnClickListener onClickListener) {
        this(context, onClickListener, R.color.white);
    }

    public ButtonSpan(Context context, View.OnClickListener onClickListener, int colorId) {
        this.onClickListener = onClickListener;
        this.context = context;
        this.colorId = colorId;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setColor(context.getResources().getColor(colorId));
        ds.setTextSize(dip2px(16));
        ds.setUnderlineText(false);
    }

    @Override
    public void onClick(View widget) {
        if (onClickListener != null) {
            onClickListener.onClick(widget);
        }
    }

    public static int dip2px(float dipValue) {
        final float scale = Resources.getSystem().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }
}

3.xml布局

<com.app.grfwtyd.util.ExpandTextView
    android:id="@+id/tv4"
    android:textSize="14dp"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    android:layout_marginTop="4dp"
    android:textColor="#FF999999"
    android:layout_width="match_parent"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:ellipsize="end"
    android:layout_height="wrap_content" />

4.使用

@Bind(R.id.tv4)
ExpandTextView tv4;
a.
//如果是在Activity中直接使用tv4.initWidth(getWindowManager().getDefaultDisplay().getWidth());即可,eg:
tv4.initWidth(getWindowManager().getDefaultDisplay().getWidth());

b.
//如果是在adapter中或其他地方使用
A.
定义变量
public static NewHCPActivity instance;

B.

onCreate方法中

instance = this;

C.在onDestroy方法中

@Override
protected void onDestroy() {
    super.onDestroy();
    instance = null;
}
D.在adapter中使用
tv4.initWidth(NewHCPActivity.instance.getWidth()-200);
// 设置最大行数
tv4.setMaxLines(2);
String content = "特价恢复健康的撒回复就可获得撒即可发货的撒回复的手机卡回复健康和福建大厦发你的数据返回刀剑三发货单进沙发的刷卡号风刀霜剑开发的设计费和实到";
tv4.setCloseText(content);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
YCExpandView01.该库介绍02.效果展示03.如何使用04.注意要点05.优化问题06.部分代码逻辑01.该库介绍自定义折叠和展开布局,在不用改变原控件的基础上,就可以实现折叠展开功能,入侵性极低。主要的思路是,设置一个折叠时的布局高度,设置一个内容展开时的高度,然后利用属性动画去动态改变布局的高度。可以设置折叠和展开的监听事件,方便开发者拓展其他需求。可以设置动画的时间。可以支持支持常见的文本折叠,流失布局标签折叠,或者RecyclerView折叠等功能。十分方便,思路也比较容易理解,代码不超过300行……02.效果展示03.如何使用设置文本控件      如何切换展开和折叠//初始化操作 expand.initExpand(false ,mHeight); //设置动画时间 expand.setAnimationDuration(300); //折叠或者展开操作后的监听 expand.setOnToggleExpandListener(new ExpandLayout.OnToggleExpandListener() {     @Override     public void onToggleExpand(boolean isExpand) {         if (isExpand){             ivExpand.setBackgroundResource(R.mipmap.icon_btn_collapse);         }else {             ivExpand.setBackgroundResource(R.mipmap.icon_btn_expand);         }     } }); //折叠view expand.collapse(); //展开view expand.expand(); //查看控件是折叠还是展开状态 expand.isExpand(); //这个是置反操作 expand.toggleExpand();04.注意要点05.优化问题1.在从折叠状态到伸展状态,或者反之。只要是在动画过程中,则执行动画的过程中屏蔽事件传递2.当控件销毁后,在onDetachedFromWindow方法中,手动销毁动画3.针对折叠和伸展状态之间切换,如果动画在执行中,即使调用多次toggleExpand()方法,避免频繁调用collapse或者expand4.如果开发者使用该折叠控件时,设置折叠时的高度为0,则会抛出异常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kenadc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值