下面列出了android.text.Layout#getPrimaryHorizontal ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static float GetLetterPositionX(@NonNull TextView aView, int aLetterIndex, boolean aClamp) {
Layout layout = aView.getLayout();
if (layout == null) {
return 0;
}
float x = layout.getPrimaryHorizontal(aLetterIndex);
x += aView.getPaddingLeft();
x -= aView.getScrollX();
if (aClamp && x > (aView.getMeasuredWidth() - aView.getPaddingRight())) {
x = aView.getMeasuredWidth() - aView.getPaddingRight();
}
if (aClamp && x < aView.getPaddingLeft()) {
x = aView.getPaddingLeft();
}
return x;
}
private void translateText(Layout layout, BufferType type) {
if (layout.getLineCount() > mShowMaxLine) {
SpannableStringBuilder span = new SpannableStringBuilder();
int start = layout.getLineStart(mShowMaxLine - 1);
int end = layout.getLineVisibleEnd(mShowMaxLine - 1);
TextPaint paint = getPaint();
StringBuilder builder = new StringBuilder(ELLIPSIZE_END);
if (mTipGravity == END) {
builder.append(" ").append(mFoldText);
end -= paint.breakText(mOriginalText, start, end, false, paint.measureText(builder.toString()), null) + 1;
float x = getWidth() - getPaddingLeft() - getPaddingRight() - getTextWidth(ELLIPSIZE_END.concat(mFoldText));
while (layout.getPrimaryHorizontal(end - 1) + getTextWidth(mOriginalText.subSequence(end - 1, end).toString()) < x) {
end++;
}
end -= 2;
} else {
end -= paint.breakText(mOriginalText, start, end, false, paint.measureText(builder.toString()), null) + 1;
}
CharSequence ellipsize = mOriginalText.subSequence(0, end);
span.append(ellipsize);
span.append(ELLIPSIZE_END);
addTip(span, type);
}
}
@Override
protected void onDraw(Canvas canvas) {
int count = getLineCount();
final Layout layout = getLayout();
float xStart, xStop, xDiff;
int firstCharInLine, lastCharInLine;
for (int i = 0; i < count; i++) {
int baseline = getLineBounds(i, mRect);
firstCharInLine = layout.getLineStart(i);
lastCharInLine = layout.getLineEnd(i);
xStart = layout.getPrimaryHorizontal(firstCharInLine);
xDiff = layout.getPrimaryHorizontal(firstCharInLine + 1) - xStart;
xStop = layout.getPrimaryHorizontal(lastCharInLine - 1) + xDiff;
canvas.drawLine(xStart,
baseline + mStrokeWidth,
xStop,
baseline + mStrokeWidth,
mPaint);
}
super.onDraw(canvas);
}
/**
* Calculate the right boundary for this run (harder than it sounds). As we're a letter ahead,
* need to grab either current letter start or the end of the previous line. Also need to
* consider maxLines case, which inserts ellipses at the overflow point – don't include these.
*/
private int getRunRight(
Layout unrestrictedLayout, Layout maxLinesLayout, int currentLine, int index,
int line, boolean withinMax, boolean isMaxEllipsis, boolean isLastChar) {
int runRight;
if (line != currentLine || isLastChar) {
if (isMaxEllipsis) {
runRight = (int) maxLinesLayout.getPrimaryHorizontal(index);
} else {
runRight = (int) unrestrictedLayout.getLineMax(currentLine);
}
} else {
if (withinMax) {
runRight = (int) maxLinesLayout.getPrimaryHorizontal(index);
} else {
runRight = (int) unrestrictedLayout.getPrimaryHorizontal(index);
}
}
return runRight;
}
/**
* @param line - current line
* @param column - column of line
* @return Position (in pixels) for edittext at line and column
*/
public Point getDebugPosition(int line, int column, int gravity) {
Layout layout = getLayout();
if (layout != null) {
int pos = layout.getLineStart(line) + column;
int baseline = layout.getLineBaseline(line);
int ascent = layout.getLineAscent(line);
int offsetHorizontal = (int) layout.getPrimaryHorizontal(pos) + mLinePadding; //x
float y;
int offsetVertical = 0;
if (gravity == Gravity.BOTTOM) {
y = baseline + ascent;
if (verticalScroll != null) {
offsetVertical = (int) ((y + mCharHeight) - verticalScroll.getScrollY());
} else {
offsetVertical = (int) ((y + mCharHeight) - getScrollY());
}
return new Point(offsetHorizontal, offsetVertical);
} else if (gravity == Gravity.TOP) {
y = layout.getLineTop(line);
if (verticalScroll != null) {
offsetVertical = (int) (y - verticalScroll.getScrollY());
} else {
offsetVertical = (int) (y - getScrollY());
}
return new Point(offsetHorizontal, offsetVertical);
}
return new Point(offsetHorizontal, offsetVertical);
}
return new Point();
}
@Override
public void onPopupChangePosition() {
try {
Layout layout = getLayout();
if (layout != null) {
int pos = getSelectionStart();
int line = layout.getLineForOffset(pos);
int baseline = layout.getLineBaseline(line);
int ascent = layout.getLineAscent(line);
float x = layout.getPrimaryHorizontal(pos);
float y = baseline + ascent;
int offsetHorizontal = (int) x + mLinePadding;
setDropDownHorizontalOffset(offsetHorizontal);
int heightVisible = getHeightVisible();
int offsetVertical = 0;
if (verticalScroll != null) {
offsetVertical = (int) ((y + mCharHeight) - verticalScroll.getScrollY());
} else {
offsetVertical = (int) ((y + mCharHeight) - getScrollY());
}
int tmp = offsetVertical + getDropDownHeight() + mCharHeight;
if (tmp < heightVisible) {
tmp = offsetVertical + mCharHeight / 2;
setDropDownVerticalOffset(tmp);
} else {
tmp = offsetVertical - getDropDownHeight() - mCharHeight;
setDropDownVerticalOffset(tmp);
}
}
} catch (Exception ignored) {
}
}
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 void draw(TextView textView, Canvas canvas) {
Layout layout = textView.getLayout();
if (layout != null) {
CharSequence text = textView.getText();
if (text instanceof Spanned) {
Spanned spanned = (Spanned) text;
OverlineSpan[] spans = spanned.getSpans(0, spanned.length(), OverlineSpan.class);
if (spans != null && spans.length > 0) {
int paddingTop = textView.getTotalPaddingTop();
int paddingLeft = textView.getPaddingLeft();
int shift = (int) (textView.getTextSize() * 8f / 9f);
float thickness = textView.getTextSize() / 15f - 0.25f;
int color = textView.getCurrentTextColor();
PAINT.setColor(color);
PAINT.setStrokeWidth(thickness);
for (OverlineSpan span : spans) {
int start = spanned.getSpanStart(span);
int end = spanned.getSpanEnd(span);
int lineStart = layout.getLineForOffset(start);
int lineEnd = layout.getLineForOffset(end);
for (int i = lineStart; i <= lineEnd; i++) {
float left = i == lineStart ? layout.getPrimaryHorizontal(start) : layout.getLineLeft(i);
float right = i == lineEnd ? layout.getPrimaryHorizontal(end) : layout.getLineRight(i);
float top = layout.getLineBaseline(i) - shift + 0.5f;
canvas.drawLine(paddingLeft + left, paddingTop + top, paddingLeft + right,
paddingTop + top, PAINT);
}
}
}
}
}
}
protected void onPopupChangePosition() {
try {
Layout layout = getLayout();
if (layout != null) {
int pos = getSelectionStart();
int line = layout.getLineForOffset(pos);
int baseline = layout.getLineBaseline(line);
int ascent = layout.getLineAscent(line);
Rect bounds = new Rect();
Paint textPaint = getPaint();
String sample="A";
textPaint.getTextBounds(sample, 0, sample.length(), bounds);
int width = bounds.width()/sample.length();
float x = layout.getPrimaryHorizontal(pos);
float y = baseline + ascent;
int offsetHorizontal = (int) x + mGutterWidth;
setDropDownHorizontalOffset(offsetHorizontal);
int heightVisible = getHeightVisible();
int offsetVertical = (int) ((y + mCharHeight) - getScrollY());
int tmp = offsetVertical + getDropDownHeight() + mCharHeight;
//if (tmp < heightVisible) {
tmp = -h + ((offsetVertical*2 / (mCharHeight)) * (mCharHeight / 2))+(mCharHeight/2);
setDropDownVerticalOffset(tmp);
//((Activity)(mContext)).setTitle("ov :"+offsetVertical +" ch "+mCharHeight+" tmp"+tmp +"h "+h+"p:"+pos);
// } else {
// tmp = offsetVertical - getDropDownHeight() - mCharHeight;
// setDropDownVerticalOffset(tmp);
// ((Activity)(mContext)).setTitle(" 2 tmp :"+tmp);
// }
// int pos = getSelectionStart();
// int line = layout.getLineForOffset(pos);
// int baseline = layout.getLineBaseline(line);
// int ascent = layout.getLineAscent(line);
//
// float x = layout.getPrimaryHorizontal(pos);
// float y = baseline + ascent;
//
// int offsetHorizontal = (int) x + mGutterWidth;
// setDropDownHorizontalOffset(offsetHorizontal);
//
// // int heightVisible = getHeightVisible();
// int offsetVertical = (int) ((y + mCharHeight) - getScrollY());
//
// int tmp = offsetVertical + getDropDownHeight() + mCharHeight;
//// if (tmp < heightVisible) {
// tmp = -(offsetVertical + mCharHeight) + ((offsetVertical / mCharHeight) * (mCharHeight / 2));
// setDropDownVerticalOffset(tmp);
//// } else {
//// tmp = offsetVertical - getDropDownHeight() - mCharHeight;
//// setDropDownVerticalOffset(tmp);
//// }
}
} catch (Exception e) {
Logger.error(TAG, e);
}
}
@Override
public void setText(final CharSequence text, final BufferType type) {
mOriginalText = text;
if (TextUtils.isEmpty(text) || mShowMaxLine == 0) {
super.setText(text, type);
} else if (isExpand) {
//文字展开
SpannableStringBuilder spannable = new SpannableStringBuilder(mOriginalText);
if (isShowTipAfterExpand) {
spannable.append(mExpandText);
spannable.setSpan(new ForegroundColorSpan(mTipColor), spannable.length() - mExpandText.length(), spannable.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
super.setText(spannable, type);
int mLineCount = getLineCount();
Layout layout = getLayout();
minX = getPaddingLeft() + layout.getPrimaryHorizontal(spannable.toString().lastIndexOf(mExpandText.charAt(0)) - 1);
maxX = getPaddingLeft() + layout.getSecondaryHorizontal(spannable.toString().lastIndexOf(mExpandText.charAt(mExpandText.length() - 1)) + 1);
Rect bound = new Rect();
if (mLineCount > originalLineCount) {
//不在同一行
layout.getLineBounds(originalLineCount - 1, bound);
minY = getPaddingTop() + bound.top;
middleY = minY + getPaint().getFontMetrics().descent - getPaint().getFontMetrics().ascent;
maxY = middleY + getPaint().getFontMetrics().descent - getPaint().getFontMetrics().ascent;
} else {
//同一行
layout.getLineBounds(originalLineCount - 1, bound);
minY = getPaddingTop() + bound.top;
maxY = minY + getPaint().getFontMetrics().descent - getPaint().getFontMetrics().ascent;
}
} else {
if (!flag) {
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
flag = true;
formatText(text, type);
return true;
}
});
} else {
formatText(text, type);
}
}
}
private void draw(
@NonNull View view,
@NonNull Canvas canvas,
@NonNull Layout layout
) {
final CharSequence cs = layout.getText();
if (!(cs instanceof Spanned)) {
return;
}
final Spanned spanned = (Spanned) cs;
final int save = canvas.save();
try {
canvas.translate(view.getPaddingLeft(), view.getPaddingTop());
// TODO: block?
// TODO: we must remove _original_ spans
// TODO: cache (attach a listener?)
// TODO: editor?
final CodeSpan[] spans = spanned.getSpans(0, spanned.length(), CodeSpan.class);
if (spans != null && spans.length > 0) {
for (CodeSpan span : spans) {
final int startOffset = spanned.getSpanStart(span);
final int endOffset = spanned.getSpanEnd(span);
final int startLine = layout.getLineForOffset(startOffset);
final int endLine = layout.getLineForOffset(endOffset);
// do we need to round them?
final float left = layout.getPrimaryHorizontal(startOffset)
+ (-1 * layout.getParagraphDirection(startLine) * paddingHorizontal);
final float right = layout.getPrimaryHorizontal(endOffset)
+ (layout.getParagraphDirection(endLine) * paddingHorizontal);
final float top = getLineTop(layout, startLine, paddingVertical);
final float bottom = getLineBottom(layout, endLine, paddingVertical);
Debug.i(new RectF(left, top, right, bottom).toShortString());
if (startLine == endLine) {
canvas.drawRect(left, top, right, bottom, paint);
} else {
// draw first line (start until the lineEnd)
// draw everything in-between (startLine - endLine)
// draw last line (lineStart until the end
canvas.drawRect(
left,
top,
layout.getLineRight(startLine),
getLineBottom(layout, startLine, paddingVertical),
paint
);
for (int line = startLine + 1; line < endLine; line++) {
canvas.drawRect(
layout.getLineLeft(line),
getLineTop(layout, line, paddingVertical),
layout.getLineRight(line),
getLineBottom(layout, line, paddingVertical),
paint
);
}
canvas.drawRect(
layout.getLineLeft(endLine),
getLineTop(layout, endLine, paddingVertical),
right,
getLineBottom(layout, endLine, paddingVertical),
paint
);
}
}
}
} finally {
canvas.restoreToCount(save);
}
}