自定义TextView文本收缩,展开,例如:了解更多

项目里遇到一个需求:一段描述性内容只显示三行,如果超出了三行就在第三行尾部显示---了解更多,点击了解更多能展开全部内容,点击收起,则显示三行的内容,因为项目需求,本项目吧,展开和收起代码注释了,如有需求,取消注释过的代码就行,本项目实现的点击了解更多跳转一个新的Activity(再次用Toast代替跳转效果)

效果如下:                                 

代码如下:

MainActivity.class

package com.example.administrator.myapplication2222;

import android.annotation.SuppressLint;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Html;
import android.view.ViewTreeObserver;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private String testStr="我怕来不及,我要抱着你直到,感觉你的皱纹有,了岁月的痕迹,直到肯定你是真,的直到失去力气为,了你 我愿意动,也不能动 也,要看着你,直到感觉,你的发线有了白雪的痕迹";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final OverTextView tv_over = (OverTextView) findViewById(R.id.tv_over);
        tv_over.setText(Html.fromHtml(testStr));
        tv_over.setBackColor("#ff0000");
        tv_over.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {

                    @SuppressLint("NewApi")
                    @Override
                    public void onGlobalLayout() {
                        tv_over.replaceTips();
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                            tv_over.getViewTreeObserver()
                                    .removeOnGlobalLayoutListener(this);
                        } else {
                            tv_over.getViewTreeObserver()
                                    .removeGlobalOnLayoutListener(this);
                        }
                    }
                });
        tv_over.setOnCustomLinkClickListener(new OverTextView.OnCustomLinkClickListener() {

            @Override
            public void onCustomLinkClick() {
                Toast.makeText(MainActivity.this, "点我干嘛", Toast.LENGTH_LONG)
                        .show();
            }
        });
    }
}
 2.自定义的TextView

OverT

package com.example.administrator.myapplication2222;

import android.text.SpannableStringBuilder;
import android.widget.TextView;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.BackgroundColorSpan;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
/**
 * Created by Administrator on 2016/12/29.
 */

public class OverTextView extends TextView {
    /**
     * 文字超出时的提示信息
     */
    private String mTips = "了解更多";

    private OnCustomLinkClickListener mOnCustomLinkClickListener;

    // 点击后背景颜色显示
    private int mBackColor = -1;

    private int mStart = -1;
    private int mEnd = -1;

    public OverTextView(Context context) {
        super(context);
    }

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

    public OverTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean result = super.onTouchEvent(event);
        int action = event.getAction();

        int x = (int) event.getX();
        int y = (int) event.getY();

        x -= getTotalPaddingLeft();
        y -= getTotalPaddingTop();

        x += getScrollX();
        y += getScrollY();

        Layout layout = getLayout();
        // 获取当前点击位置所在的行
        int line = layout.getLineForVertical(y);
        // 获取当前点击位置的文本的偏移值
        int off = layout.getOffsetForHorizontal(line, x);

        CharSequence text = getText();
        if (TextUtils.isEmpty(text) || !(text instanceof Spannable)) {
            return result;
        }

        Spannable buffer = (Spannable) text;
        ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);

        if (link.length != 0) {
            if (action == MotionEvent.ACTION_DOWN) {
                mStart = buffer.getSpanStart(link[0]);
                mEnd = buffer.getSpanEnd(link[0]);
                if (mStart >= 0 && mEnd >= mStart) {
                    buffer.setSpan(new BackgroundColorSpan(getBackColor()),
                            mStart, mEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            } else if (action == MotionEvent.ACTION_UP
                    || action == MotionEvent.ACTION_CANCEL) {

                if (mStart >= 0 && mEnd >= mStart) {
                    buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT),
                            mStart, mEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

                    mStart = -1;
                    mEnd = -1;
                }
            }

            return true;
        } else {
            if (mStart >= 0 && mEnd >= mStart) {
                buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT),
                        mStart, mEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                mStart = -1;
                mEnd = -1;
            }
            Selection.removeSelection(buffer);
            return false;
        }
    }

    /**
     * 文本宽度超出TextView的范围的具体项值
     *
     * @param0表示不考虑提示文本
     * @return -1 表示没有超过TextView的范围。
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private int starOverFlow(String text, float tipsWidth) {
        if (TextUtils.isEmpty(text)) {
            return -1;
        }
        text=text.trim();
        TextPaint paint = getPaint();
        // 文字总宽度
        float width = paint.measureText(text);
        float rangeWidth = 0;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            rangeWidth = getLayout().getWidth() * getMaxLines() - tipsWidth;
        } else {
            rangeWidth = getLayout().getWidth() * getLayout().getLineCount()
                    - tipsWidth;
        }
        if (width > rangeWidth) {
         /*
          * \u2026为文本超出时系统显示的省略号
          */
            return paint.breakText(text, true,
                    rangeWidth - paint.measureText("\u2026"), null);
        } else {
            return -1;
        }
    }

    /**
     * 测量文字宽度
     *
     * @param text
     * @return
     */
    private float measureTextWidth(String text) {
        if (TextUtils.isEmpty(text)) {
            return 0;
        }
        TextPaint paint = getPaint();
        return paint.measureText(text);
    }

    /**
     * 替换文本
     *
     * 请在该控件显示后调用
     *
     * @param tips
     *            要替换的提示文本
     */
    public void replaceTips(String tips) {
        if (TextUtils.isEmpty(tips)) {
            tips = mTips;
        }
        // 算出提示文本附加的位置
        int index = starOverFlow(getText().toString(), measureTextWidth(tips.trim()));
        if (index > 0) {
            /**
             * 多截取几个,避免显示不统一(有些文本时,提示文本可能会显示不全)
             */
        String sl="…";//此省略号为中文的。
            String willText = getText().toString()
                    .substring(0, index-sl.length());
            willText = willText +"… "+ tips;
            SpannableStringBuilder s = new SpannableStringBuilder(willText);
            SpannableString style = new SpannableString(s);
            // style.setSpan(new ForegroundColorSpan(Color.BLUE),
            // willText.indexOf(tips), willText.length(),
            // Spanned.SPAN_INCLUSIVE_INCLUSIVE);
            MyClickSpan myClickSpan = new MyClickSpan();
            style.setSpan(myClickSpan, willText.indexOf(tips),
                    willText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            setMovementMethod(LinkMovementMethod.getInstance());
            setText(style);

            // // 标识文本可被编辑
            // setText(willText, BufferType.EDITABLE);
            // Editable et = getEditableText();
            // et.setSpan(new ForegroundColorSpan(Color.BLUE),
            // willText.indexOf(tips), willText.length(),
            // Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        }
    }

    /**
     * 获取点击后背景颜色显示,默认灰色
     *
     * @return
     */
    public int getBackColor() {
        if (mBackColor == -1) {
            return Color.GRAY;
        }
        return mBackColor;
    }

    /**
     * 设置点击后背景颜色
     *
     * @param mBackColor
     *            请勿填写颜色资源ID
     */
    public void setBackColor(int mBackColor) {
        this.mBackColor = mBackColor;
    }

    /**
     * 设置点击后背景颜色
     *
     * @param mBackColor
     *            颜色值 如:#000000 #00000000 或者 green red 的颜色名称
     */
    public void setBackColor(String mBackColor) {
        if (!TextUtils.isEmpty(mBackColor)) {
            this.mBackColor = Color.parseColor(mBackColor);
        }
    }

    /**
     * 使用颜色资源ID设置点击后背景颜色
     *
     * @param resId
     *            资源ID     */
    public void setBackColorByRes(int resId) {
        try {
            this.mBackColor = getContext().getResources().getColor(resId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置自定义的链接的点击事件
     *
     * @param mOnCustomLinkClickListener
     */
  public void setOnCustomLinkClickListener(
            OnCustomLinkClickListener mOnCustomLinkClickListener) {
        this.mOnCustomLinkClickListener = mOnCustomLinkClickListener;
    }

    /**
     * 替换文本
     *
     * 请在该控件显示后调用
     */
    public void replaceTips() {
        replaceTips(null);
    }

    public class MyClickSpan extends ClickableSpan {

        @Override
        public void onClick(View arg0) {
            Spannable spannable = (Spannable) ((TextView) arg0).getText();
            Selection.removeSelection(spannable);
            if (mOnCustomLinkClickListener != null) {
                mOnCustomLinkClickListener.onCustomLinkClick();
            }
        }

        @Override
        public void updateDrawState(TextPaint ds) {
            ds.setUnderlineText(false);
            ds.setColor(Color.BLUE);
        }
    }

    /**
     * 自定义的链接点击事件
     *
     * @author frj
     *
     */
 public interface OnCustomLinkClickListener {
        /**
         * 自定义链接点击
         */
        void onCustomLinkClick();
    }

}
extView.class


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值