下面列出了android.text.Layout#getLineCount ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Performs a scroll down action.
* Scrolls down by the specified number of lines.
*
* @param widget The text view.
* @param buffer The text buffer.
* @param amount The number of lines to scroll by. Must be at least 1.
* @return True if the event was handled.
* @hide
*/
protected boolean scrollDown(TextView widget, Spannable buffer, int amount) {
final Layout layout = widget.getLayout();
final int innerHeight = getInnerHeight(widget);
final int bottom = widget.getScrollY() + innerHeight;
int bottomLine = layout.getLineForVertical(bottom);
if (layout.getLineTop(bottomLine + 1) < bottom + 1) {
// Less than a pixel of this line is out of view,
// so we must have tried to make it entirely in view
// and now want the next line to be in view instead.
bottomLine += 1;
}
final int limit = layout.getLineCount() - 1;
if (bottomLine <= limit) {
bottomLine = Math.min(bottomLine + amount - 1, limit);
Touch.scrollTo(widget, layout, widget.getScrollX(),
layout.getLineTop(bottomLine + 1) - innerHeight);
return true;
}
return false;
}
@Override
protected void drawFrame(Canvas canvas) {
Layout layout = mHTextView.getLayout();
int gapIndex = 0;
for (int i = 0; i < layout.getLineCount(); i++) {
int lineStart = layout.getLineStart(i);
int lineEnd = layout.getLineEnd(i);
float lineLeft = layout.getLineLeft(i);
float lineBaseline = layout.getLineBaseline(i);
String lineText = mText.subSequence(lineStart, lineEnd).toString();
for (int c = 0; c < lineText.length(); c++) {
int alpha = alphaList.get(gapIndex);
mPaint.setAlpha((int) ((255 - alpha) * progress + alpha));
canvas.drawText(String.valueOf(lineText.charAt(c)), lineLeft, lineBaseline, mPaint);
lineLeft += gapList.get(gapIndex++);
}
}
}
/**
* 裁剪文本至固定行数
* @param text 源文本
* @return 字符串
*/
private String tailorText(String text){
String destStr = text + ELLIPSIS + getUnfoldText();
Layout layout = makeTextLayout(destStr);
//如果行数大于固定行数
if(layout.getLineCount() > getFoldLine()){
int index = layout.getLineEnd(getFoldLine());
if(text.length() < index){
index = text.length();
}
//从最后一位逐渐试错至固定行数
String subText = text.substring(0, index-1);
return tailorText(subText);
}else{
return destStr;
}
}
/**
* Returns the width of the layout.
*
* @param layout The layout.
* @return The width of the layout.
*/
public static int getWidth(Layout layout) {
if (layout == null) {
return 0;
}
// Supplying VERY_WIDE will make layout.getWidth() return a very large value.
int count = layout.getLineCount();
int maxWidth = 0;
for (int i = 0; i < count; i++) {
maxWidth = Math.max(maxWidth, (int) layout.getLineRight(i));
}
return maxWidth;
}
/**
* 按行分割文本
*/
private void spliteLineData(Layout layout,String text){
mLineDataList.clear();
int lineCount = layout.getLineCount();
Log.d("hyh", "AutomaticEditText: spliteLineData: text="+text+" ,lineCount="+lineCount);
for (int i = 0; i < lineCount; i++) {
int start = layout.getLineStart(i);
int end = layout.getLineEnd(i);
String rowStr = text.substring(start,end);
//去除掉换行符
if(rowStr.contains(SYM_CHANGE_LINE)){
rowStr = rowStr.replace(SYM_CHANGE_LINE,"");
}
CustomSpanData customTextSpanData = new CustomSpanData.Builder(start,end)
.setSpanType(TYPE_ABS_SIZE_SPAN)
.setTextSize(UNIT_PX,mLayoutHelper.getFontSize())
.build();
LineData lineData = new LineData(rowStr,customTextSpanData);
Log.d("hyh", "AutomaticEditText: spliteLineData: lineData="+lineData.toString());
mLineDataList.add(lineData);
}
}
private void drawLoadingMsg(Canvas canvas, String msg, float offset) {
Layout tempLayout = new StaticLayout(msg, mTextPaint, mVisibleWidth, Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
List<String> linesData = new ArrayList<>();
for (int i = 0; i < tempLayout.getLineCount(); i++) {
linesData.add(msg.substring(tempLayout.getLineStart(i), tempLayout.getLineEnd(i)));
}
float pivotY = (mDisplayHeight - textInterval * linesData.size()) / 2f - offset;
for (String str : linesData) {
float textWidth = mTextPaint.measureText(str);
float pivotX = (mDisplayWidth - textWidth) / 2;
canvas.drawText(str, pivotX, pivotY, mTextPaint);
pivotY += textInterval;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (needCheckDevice && isVivoApi22()) {
int width = getMeasuredWidth();
CharSequence charSequence = getText();
Layout layout = createWorkingLayout(charSequence, getPaint(), width);
float dotWidth = getPaint().measureText(DOT_SUFFIX);
int lineCount = layout.getLineCount();
Log.d(TAG, "onMeasure , lineCount : " + lineCount);
// 多行且第一行未占满
if (lineCount > 1 && Math.abs(width - layout.getLineWidth(0)) > dotWidth) {
Log.d(TAG, "onMeasure , firstLineEndIndex : " + layout.getLineEnd(0));
int index = layout.getLineEnd(1);
while (true) {
index--;
charSequence = charSequence.subSequence(0, index);
charSequence = SpannableStringBuilder.valueOf(charSequence).append(DOT_SUFFIX);
layout = createWorkingLayout(charSequence, getPaint(), width);
if (layout.getLineCount() == 1 && (width - layout.getLineWidth(0) <= dotWidth || index <= 10)) {
mLayout = layout;
break;
}
}
}
needCheckDevice = false;
}
}
/**
* Performs a scroll page up action.
* Scrolls down by one page.
*
* @param widget The text view.
* @param buffer The text buffer.
* @return True if the event was handled.
* @hide
*/
protected boolean scrollPageDown(TextView widget, Spannable buffer) {
final Layout layout = widget.getLayout();
final int innerHeight = getInnerHeight(widget);
final int bottom = widget.getScrollY() + innerHeight + innerHeight;
int bottomLine = layout.getLineForVertical(bottom);
if (bottomLine <= layout.getLineCount() - 1) {
Touch.scrollTo(widget, layout, widget.getScrollX(),
layout.getLineTop(bottomLine + 1) - innerHeight);
return true;
}
return false;
}
@Override
protected void onDraw(Canvas canvas) {
TextPaint paint = getPaint();
paint.setColor(getCurrentTextColor());
paint.drawableState = getDrawableState();
mViewWidth = getMeasuredWidth();
String text = getText().toString();
mLineY = 0;
mLineY += getTextSize();
Layout layout = getLayout();
// layout.getLayout()在4.4.3出现NullPointerException
if (layout == null) {
return;
}
Paint.FontMetrics fm = paint.getFontMetrics();
int textHeight = (int) (Math.ceil(fm.descent - fm.ascent));
textHeight = (int) (textHeight * layout.getSpacingMultiplier() + layout
.getSpacingAdd());
for (int i = 0; i < layout.getLineCount(); i++) {
int lineStart = layout.getLineStart(i);
int lineEnd = layout.getLineEnd(i);
float width = StaticLayout.getDesiredWidth(text, lineStart,
lineEnd, getPaint());
String line = text.substring(lineStart, lineEnd);
if (needScale(line)) {
drawScaledText(canvas, lineStart, line, width);
} else {
canvas.drawText(line, 0, mLineY, paint);
}
mLineY += textHeight;
}
}
@VisibleForTesting
public static int resolveWidth(
int widthSpec, Layout layout, boolean minimallyWide, int minimallyWideThreshold) {
final int fullWidth = SizeSpec.resolveSize(widthSpec, layout.getWidth());
if (minimallyWide && layout.getLineCount() > 1) {
final int minimalWidth = SizeSpec.resolveSize(widthSpec, LayoutMeasureUtil.getWidth(layout));
if (fullWidth - minimalWidth > minimallyWideThreshold) {
return minimalWidth;
}
}
return fullWidth;
}
public static WritableArray getFontMetrics(CharSequence text, Layout layout, TextPaint paint, Context context) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
WritableArray lines = Arguments.createArray();
// To calculate xHeight and capHeight we have to render an "x" and "T" and manually measure their height.
// In order to get more precision than Android offers, we blow up the text size by 100 and measure it.
// Luckily, text size affects rendering linearly, so we can do this trick.
TextPaint paintCopy = new TextPaint(paint);
paintCopy.setTextSize(paintCopy.getTextSize() * AMPLIFICATION_FACTOR);
Rect capHeightBounds = new Rect();
paintCopy.getTextBounds(CAP_HEIGHT_MEASUREMENT_TEXT, 0, CAP_HEIGHT_MEASUREMENT_TEXT.length(), capHeightBounds);
double capHeight = capHeightBounds.height() / AMPLIFICATION_FACTOR / dm.density;
Rect xHeightBounds = new Rect();
paintCopy.getTextBounds(X_HEIGHT_MEASUREMENT_TEXT, 0, X_HEIGHT_MEASUREMENT_TEXT.length(), xHeightBounds);
double xHeight = xHeightBounds.height() / AMPLIFICATION_FACTOR / dm.density;
for (int i = 0; i < layout.getLineCount(); i++) {
Rect bounds = new Rect();
layout.getLineBounds(i, bounds);
WritableMap line = Arguments.createMap();
line.putDouble("x", layout.getLineLeft(i) / dm.density);
line.putDouble("y", bounds.top / dm.density);
line.putDouble("width", layout.getLineWidth(i) / dm.density);
line.putDouble("height", bounds.height() / dm.density);
line.putDouble("descender", layout.getLineDescent(i) / dm.density);
line.putDouble("ascender", -layout.getLineAscent(i) / dm.density);
line.putDouble("baseline", layout.getLineBaseline(i) / dm.density);
line.putDouble("capHeight", capHeight);
line.putDouble("xHeight", xHeight);
line.putString(
"text", text.subSequence(layout.getLineStart(i), layout.getLineEnd(i)).toString());
lines.pushMap(line);
}
return lines;
}
@Nullable
protected CharSequence getNextLine(Editable editable, Layout layout, int currentLine) {
if (currentLine + 1 > layout.getLineCount() - 1) return null;
int lineStart = layout.getLineStart(currentLine + 1);
int lineEnd = layout.getLineEnd(currentLine + 1);
return editable.subSequence(lineStart, lineEnd);
}
private boolean isContentEllipsised(TextView textView) {
Layout layout = textView.getLayout();
if (layout != null) {
int lineCount = layout.getLineCount();
for (int i = 0; i < lineCount; i++) {
if (layout.getEllipsisCount(i) > 0) {
return true;
}
}
}
return false;
}
private void translateText(Layout layout, BufferType type) {
originalLineCount = layout.getLineCount();
if (layout.getLineCount() > mShowMaxLine) {
isOverMaxLine = true;
SpannableStringBuilder span = new SpannableStringBuilder();
int start = layout.getLineStart(mShowMaxLine - 1);
int end = layout.getLineEnd(mShowMaxLine - 1);
if (mTipGravity == END) {
TextPaint paint = getPaint();
StringBuilder builder = new StringBuilder(ELLIPSIZE_END).append(mFoldText);
end -= paint.breakText(mOriginalText, start, end, false, paint.measureText(builder.toString()), null);
float x = getWidth() - getPaddingLeft() - getPaddingRight() - getTextWidth(mFoldText);
while (layout.getPrimaryHorizontal(end - 1) + getTextWidth(mOriginalText.subSequence(end - 1, end).toString()) < x) {
end++;
}
end--;
} else {
end--;
}
CharSequence ellipsize = mOriginalText.subSequence(0, end);
span.append(ellipsize);
span.append(ELLIPSIZE_END);
if (mTipGravity != END) {
span.append("\n");
}
super.setText(span, type);
} else {
isOverMaxLine = false;
}
}
public static boolean isEllipsed(@NonNull TextView textView) {
Layout layout = textView.getLayout();
if (layout != null) {
int lines = layout.getLineCount();
if (lines > 0) {
return IntStream.range(0, lines).anyMatch(line -> layout.getEllipsisCount(line) > 0);
}
}
return false;
}
/**
* 判断是否需要更新文本
* @return
*/
private boolean isUpdateText(Layout layout,String text){
boolean update = false;
if(!mLastText.equals(text)) {
update = true;
}else{
int lineCount = layout.getLineCount();
int size = mLineDataList.size();
if(lineCount != size){
update = true;
}else{
for (int i = 0; i < lineCount; i++) {
int start = layout.getLineStart(i);
int end =layout.getLineEnd(i);
String rowStr = text.substring(start, end);
//去除掉换行符
if(rowStr.contains(SYM_CHANGE_LINE)){
rowStr = rowStr.replace(SYM_CHANGE_LINE,"");
}
LineData lineData = mLineDataList.get(i);
String lineText = lineData.getLineText();
if (!rowStr.equals(lineText)) {
//原本的每行文字跟现在的每行文字不相同,说明排版变了,需要重新更新文本
update = true;
break;
}
}
}
}
return update;
}
/**
* Find the number of lines of text which must be shown in order to display the character at
* a given index.
*/
private int getLineForIndex(int index) {
Layout layout = getLayout();
int endLine = 0;
while (endLine < layout.getLineCount() && layout.getLineEnd(endLine) < index) {
endLine++;
}
// Since endLine is an index, add 1 to get the number of lines.
return endLine + 1;
}
/**
* Calculates the maximum width line in a text layout.
*
* @param textLayout The text layout
* @return The maximum length line
*/
public static float calculateMaxTextWidth(@Nullable final Layout textLayout)
{
float maxTextWidth = 0f;
if (textLayout != null)
{
for (int i = 0, count = textLayout.getLineCount(); i < count; i++)
{
maxTextWidth = Math.max(maxTextWidth, textLayout.getLineWidth(i));
}
}
return maxTextWidth;
}
private void drawErrorMsg(Canvas canvas, String msg, float offset) {
Layout tempLayout = new StaticLayout(msg, mTextPaint, mVisibleWidth, Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
List<String> linesData = new ArrayList<>();
for (int i = 0; i < tempLayout.getLineCount(); i++) {
linesData.add(msg.substring(tempLayout.getLineStart(i), tempLayout.getLineEnd(i)));
}
float pivotY = (mDisplayHeight - textInterval * linesData.size()) / 3f - offset;
for (String str : linesData) {
float textWidth = mTextPaint.measureText(str);
float pivotX = (mDisplayWidth - textWidth) / 2;
if (readBookControl.getLoadingAmin() && msg.equals(mContext.getString(R.string.loading))) {
//加载中替换为动画
}else{
canvas.drawText(str, pivotX, pivotY, mTextPaint);
}
pivotY += textInterval;
}
//加载中特殊绘制
if(msg.equals(mContext.getString(R.string.loading))){
/*
mTextPaint.setTextSize(40);
// 先绘制背景色文字
mTextPaint.setColor(Color.parseColor("#808080"));
//绘制 文字
Rect rect = new Rect(0, 0, mDisplayWidth, mDisplayHeight);
mTextPaint.setTextAlign(Paint.Align.CENTER);
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
float top = metrics.top;
float bottom = metrics.bottom;
int centerY = (int) (rect.centerY() - top / 2 - bottom / 2);
canvas.drawText("搜神", rect.centerX(), centerY, mTextPaint);
Log.d("ss","ddd");
// 生成闭合波浪路径
Path mPath = getActionPath(50);
// 将Canvas按照Path的规则进行裁剪
Paint mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.parseColor("#000000"));
canvas.clipPath(mPath);
canvas.drawCircle(mDisplayWidth / 2, mDisplayHeight / 2, mDisplayWidth / 2, mPaint);
mTextPaint.setColor(Color.WHITE);
canvas.drawText("搜神", rect.centerX(), centerY, mTextPaint);
*/
}
}
@Override
protected void onDraw(Canvas canvas) {
TextPaint paint = getPaint();
paint.setColor(getCurrentTextColor());
// 返回绘制状态的资源ID数组表示视图的当前状态
paint.drawableState = getDrawableState();
// 对View上的内容进行测量后得到的View内容占据的宽度
// 前提是你必须在父布局的onLayout()方法或者此View的onDraw()方法里调用measure(0,0);
// 否则你得到的结果和getWidth()得到的结果一样。
mViewWidth = getMeasuredWidth();
// 获取文本
String text = getText().toString();
mLineY = 0;
mLineY += getTextSize();
// 获取用于显示当前文本的布局
Layout layout = getLayout();
if (layout == null) {
return;
}
Paint.FontMetrics fm = paint.getFontMetrics();
int textHeight = (int) (Math.ceil(fm.descent - fm.ascent));
textHeight = (int) (textHeight * layout.getSpacingMultiplier() + layout.getSpacingAdd());
for (int i = 0; i < layout.getLineCount(); i++) {
// 返回文本中的指定行开头的偏移
int lineStart = layout.getLineStart(i);
// 返回文本中的指定行最后一个字符的偏移
int lineEnd = layout.getLineEnd(i);
float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, getPaint());
String line = text.substring(lineStart, lineEnd);
if (line.equals("")) {
break;
}
if (i < layout.getLineCount() - 1) {
if (needScale(line)) {
drawScaledText(canvas, lineStart, line, width);
} else {
canvas.drawText(line, 0, mLineY, paint);
}
} else {
canvas.drawText(line, 0, mLineY, paint);
}
// 增加行高
mLineY += textHeight;
}
}