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