Android TextView 判断文字内容是否超出显示省略号
2015-11-21 20:56
741 查看
TextView 判断文字内容是否超出显示省略号
最近在做一个类似于QQ空间的一个社交圈的模块的开发。有一个需求是当用户发表的内容超出4行时,显示一个按钮,点击按钮展示全文。我还真没有发现TextView有获取文本内容有没有显示省略号这个方法。没办法,只能自己想办法了。想法和思路
textview既然自己会显示省略号,内部肯定有算法判断了内容是否超出最大行数的,我是不是可以找到这个方法,或者找到这个方法的返回值呢?
定位TextView的源代码
首先定位到onDraw()方法,准备查看text的绘制,再通过绘制的内容去找判断文本内容判断的代码,结果发现我想的太简单的,onDraw()中根本就没有使用canvas.drawText方法,我就纳闷了,继续看onDraw()方法,在最后发现在这行代码:
final int cursorOffsetVertical = voffsetCursor - voffsetText; Path highlight = getUpdatedHighlightPath(); if (mEditor != null) { mEditor.onDraw(canvas, layout, highlight, mHighlightPaint, cursorOffsetVertical); } else { layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical); } if (mMarquee != null && mMarquee.shouldDrawGhost()) { final float dx = mMarquee.getGhostOffset(); canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f); layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical); }
找到这行代码,
layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
打开这个Layout类的layout对象的draw方法:
public void draw(Canvas canvas, Path highlight, Paint highlightPaint, int cursorOffsetVertical) { final long lineRange = getLineRangeForDraw(canvas); int firstLine = TextUtils.unpackRangeStartFromLong(lineRange); int lastLine = TextUtils.unpackRangeEndFromLong(lineRange); if (lastLine < 0) return; drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical, firstLine, lastLine); drawText(canvas, firstLine, lastLine); }
看到这里已经明白了,文字是在这个Layout类里进行绘制的,看下这个Layout类的注释
/** * A base class that manages text layout in visual elements on * the screen. * <p>For text that will be edited, use a {@link DynamicLayout}, * which will be updated as the text changes. * For text that will not change, use a {@link StaticLayout}. */ public abstract class Layout {...
意思就是管理文字布局的一个基类。也就是文字是通过Layout的子类来一行一行布局的。好了,原理大致懂了。接着发现Layout类里有一个方法:
/** * Returns the number of characters to be ellipsized away, or 0 if * no ellipsis is to take place. */ public abstract int getEllipsisCount(int line);
也就是获取省略的字符数目,这下好了,可以通过这个方法来获取省略的字符数,如果此方法返回大于0则说明文字肯定超内容了。
实现方法
想要调用这个getEllipsisCount()方法必须先拿到TextView中的mLayout对象。所以我重写了TextView,并且通过反射字段的方式拿到了这个mLayout对象。
/** * <p> * <span style="color: purple;"> * <em>check if the text content has ellipsis </em></span> * </p> * * @return if the text content over maxlines */ public boolean checkOverLine() { int maxLine = getMaxLines(); try { Field field = getClass().getSuperclass().getDeclaredField("mLayout"); field.setAccessible(true); Layout mLayout = (Layout) field.get(this); if (mLayout == null) return false; isOverSize = mLayout.getEllipsisCount(maxLine - 1) > 0 ? true : false; } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } return isOverSize; }
完整的自定义TextView的代码:
package com.cc.testndk;
import java.lang.reflect.Field;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.text.Layout;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.TextView;
/**
* <p style="color:purple">
* If you want to check if the text content is over max size, you must set a
* ellipsize type and maxline in xml or see {@link #setMaxLines(int)} and
* {@link #setEllipsize(android.text.TextUtils.TruncateAt)}<br>
* Because of invalidate is delayed,so you must use
* {@link OnOverSizeChangedListener} call the callback method
* {@link OnOverSizeChangedListener.onChanged(boolean isOverSize)}.
* </p>
*
* @author Super.Yuan <span style="color:green"> Feel free to contact me:
* <a href="mailto:462086630@qq.com">462086630@qq.com</a></span>
*
*/
public class CheckOverSizeTextView extends TextView {
protected boolean isOverSize;
private OnOverSizeChangedListener changedListener;
public CheckOverSizeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public CheckOverSizeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CheckOverSizeTextView(Context context) {
super(context);
init();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (changedListener != null) {
changedListener.onChanged(checkOverLine());
}
}
private void init() {
// invalidate when layout end
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (changedListener != null) {
changedListener.onChanged(checkOverLine());
}
}
});
}
/** * <p> * <span style="color: purple;"> * <em>check if the text content has ellipsis </em></span> * </p> * * @return if the text content over maxlines */ public boolean checkOverLine() { int maxLine = getMaxLines(); try { Field field = getClass().getSuperclass().getDeclaredField("mLayout"); field.setAccessible(true); Layout mLayout = (Layout) field.get(this); if (mLayout == null) return false; isOverSize = mLayout.getEllipsisCount(maxLine - 1) > 0 ? true : false; } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } return isOverSize; }
public boolean isOverSize() {
return isOverSize;
}
public void displayAll() {
setMaxLines(Integer.MAX_VALUE);
setEllipsize(null);
}
public void hide(int maxlines) {
setEllipsize(TruncateAt.END);
setMaxLines(maxlines);
}
// set a listener for callback
public OnOverSizeChangedListener getChangedListener() {
return changedListener;
}
public void setOnOverLineChangedListener(OnOverSizeChangedListener changedListener) {
this.changedListener = changedListener;
}
public interface OnOverSizeChangedListener {
/**
* <span style="color:purple">when invalide,the method will be called
* and tell you whether the content text is over size
*
* @param isOverLine
* whether content text is over size
*/
public void onChanged(boolean isOverSize);
};
}
测试的Activity代码:
package com.cc.testndk; import java.util.ArrayList; import java.util.List; import com.cc.testndk.CheckOverSizeTextView.OnOverSizeChangedListener; import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView lv = (ListView) findViewById(R.id.lv); final List<String> data = new ArrayList<String>(); String str = "LongTextLongTextLongTextLongTextLongTextLongTextLongTextLongTextLongText"; String str2 = "这是第二个长的文本,如果这个文本超出最大行数的话并且设置了走出显示为...的话,就会显示红色哦。"; String str3 = "大家好我是CC。如果这个文本超出最大行数的话并且设置了走出显示为...的话,就会显示红色哦。"; for (int i = 0; i < 40; i++) { if (i == 3) data.add(str); else if (i == 5) { data.add(str2); } else if (i == 13) { data.add(str3); } else { data.add("shortText" + i); } } //set a adapter. lv.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data) { @Override public View getView(int position, View convertView, ViewGroup parent) { convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null); final CheckOverSizeTextView tv = (CheckOverSizeTextView) convertView.findViewById(R.id.tv); tv.setText(data.get(position)); tv.setOnOverLineChangedListener(new OnOverSizeChangedListener() { @Override public void onChanged(boolean isOverLine) { if (isOverLine) { tv.setBackgroundColor(Color.RED); } else { tv.setBackgroundColor(Color.WHITE); } } }); //read all. convertView.findViewById(R.id.btn_readall).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (tv.isOverSize()) { tv.displayAll(); } else { tv.hide(1); } } }); return convertView; } }); } }
效果图:
相关文章推荐
- Android如何让Handler中内部run停止(runnable/thread)
- 野人学Android第二弹——照片的拍摄与存储(一)
- 实现Android图片轮播
- 【FastDev4Android框架开发】RecyclerView完全解析之结合AA(Android Annotations)注入框架实例(三十)
- Android和JS的简单交互
- Android的Service了解和两种启动方式
- Android中对Apk加固(加壳)续篇之---对Native层(so文件)进行加固
- 深入剖析Android四大组件(七)——Activity启动的4个阶段
- android轮询最佳实践service+AlarmManager+Thread
- Android Studio 安装
- 详解Android四种基本布局
- PC/SC在android上的移植
- Android中的Handler的用法和用Handler进行更新版本
- Android 使用百度LBS SDK(六)轨迹回放
- Android逆向之旅---基于对so中的函数加密技术实现so加固
- android手机震动代码
- Android对不同DPI的dimen选择优先级问题
- 《第一行代码--Android》读书笔记之使用通知和多媒体
- Android数据存储——SharedPreferences、File、Sqlite
- android压缩图片Demo