您的位置:首页 > 移动开发 > Android开发

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;
}
});
}
}


效果图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: