下面列出了android.graphics.Paint#FontMetricsInt ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public int getSize(@NonNull Paint paint, CharSequence text,
@IntRange(from = 0) int start, @IntRange(from = 0) int end,
@Nullable Paint.FontMetricsInt fm) {
Drawable d = getCachedDrawable();
Rect rect = d.getBounds();
if (fm != null) {
fm.ascent = -rect.bottom;
fm.descent = 0;
fm.top = fm.ascent;
fm.bottom = 0;
}
return rect.right;
}
@Test
public void evenLineHeightShouldIncreaseAllMetricsProportionally() {
CustomLineHeightSpan customLineHeightSpan = new CustomLineHeightSpan(22);
Paint.FontMetricsInt fm = new Paint.FontMetricsInt();
fm.top = -10;
fm.ascent = -5;
fm.descent = 5;
fm.bottom = 10;
customLineHeightSpan.chooseHeight("Hi", 0, 2, 0, 0, fm);
// Since line height is even it should be equally added to top and bottom.
assertThat(fm.top).isEqualTo(-11);
assertThat(fm.ascent).isEqualTo(-11);
assertThat(fm.descent).isEqualTo(11);
assertThat(fm.bottom).isEqualTo(11);
assertThat(fm.bottom - fm.top).isEqualTo(22);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
baseline = (mHeight - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
}
@Override
public int getSize(@NonNull Rect outRect, @NonNull Paint paint, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, @Nullable Paint.FontMetricsInt fm) {
int width = super.getSize(outRect, paint, text, start, end, fm);
if (includePad) {
shape.resize(frame.right - strokeWidth, fontMetricsInt.bottom - fontMetricsInt.top - strokeWidth);
} else {
shape.resize(frame.right - strokeWidth, fontMetricsInt.descent - fontMetricsInt.ascent - strokeWidth);
}
return width;
}
/**
* 绘制文字
*
* @param canvas 画布
* @param paint 画笔
* @param text 画的文字
*/
private void drawText(Canvas canvas, Paint paint, String text) {
//画布的大小
Rect targetRect = new Rect(0, 0, width, height);
Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
// 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX()
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(text, targetRect.centerX(), baseline, paint);
}
@Override
public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) {
fm.top *= LINE_HEIGHT;
fm.ascent *= LINE_HEIGHT;
fm.descent *= LINE_HEIGHT;
fm.bottom *= LINE_HEIGHT;
}
private void drawTextBackground(Canvas canvas, int paintX, int paintY, int advance) {
Paint.FontMetricsInt metrics = _brush.getFontMetricsInt();
canvas.drawRect(paintX,
paintY + metrics.ascent,
paintX + advance,
paintY + metrics.descent,
_brush);
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
if (fm == null) {
fm = new Paint.FontMetricsInt();
}
if (fontMetrics == null) {
int sz = super.getSize(paint, text, start, end, fm);
int offset = AndroidUtilities.dp(8);
int w = AndroidUtilities.dp(10);
fm.top = -w - offset;
fm.bottom = w - offset;
fm.ascent = -w - offset;
fm.leading = 0;
fm.descent = w - offset;
return sz;
} else {
if (fm != null) {
fm.ascent = fontMetrics.ascent;
fm.descent = fontMetrics.descent;
fm.top = fontMetrics.top;
fm.bottom = fontMetrics.bottom;
}
if (getDrawable() != null) {
getDrawable().setBounds(0, 0, size, size);
}
return size;
}
}
private void drawText(Canvas canvas, float progress_degree) {
final String sDegree = String.valueOf(Math.round(progress_degree * 100));
final Rect rect = bounds;
publicPaint.setStyle(Paint.Style.FILL);
publicPaint.setTextSize(getProgressTextSize());
publicPaint.setTextAlign(Paint.Align.CENTER);
Paint.FontMetricsInt fontMetrics = publicPaint.getFontMetricsInt();
int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2;
canvas.drawText(sDegree, rect.centerX(), baseline, publicPaint);
publicPaint.getTextBounds(sDegree, 0, sDegree.length(), textBounds);
publicPaint.setTextSize(getProgressTextSize() / 3);
publicPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText(STR_PERCENT, rect.centerX() + textBounds.width() / 2 + .1f * radius, baseline, publicPaint);
}
public EmojiSpan(Drawable d, int verticalAlignment, int s, Paint.FontMetricsInt original) {
super(d, verticalAlignment);
init(s, original, false);
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
return (int) paint.measureText(text, start, end);
}
/**
* 画中间大的圆环,先画背景,后画绿色进度
* 半径:view_radius - CIRCLE_GAP * mDividerWidth
*
* @param canvas 画布
*/
private void drawCircle(Canvas canvas) {
Paint textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setColor(mCircleWhite);
textPaint.setTextSize(mOutIndicatorSize); // TODO: 16/6/20
float textHeight = ViewUtils.getTextHeight(textPaint);
float perAngle = CIRCLE_SWEEP_ANGLE / (mEndIndicator - mStartIndicator);
// 环的半径
int radius = (int) (getViewRadius() - CIRCLE_GAP * mDividerWidth);
// 文字的半径,参考:http://blog.csdn.net/aigestudio/article/details/41447349
Paint.FontMetricsInt fmi = textPaint.getFontMetricsInt();
float textRadius = radius - Math.abs(fmi.bottom + fmi.top) / 2;
RectF oval = new RectF(
getCenterX() - radius,
getCenterY() - radius,
getCenterX() + radius,
getCenterY() + radius);
Path path = new Path();
path.addCircle(getCenterX(), getCenterY(), textRadius, Path.Direction.CW);//顺时针绘制(or CCW)
Paint circlePaint = new Paint();
circlePaint.setAntiAlias(true);
circlePaint.setStrokeWidth(textHeight + CIRCLE_STROKE_WIDTH);
circlePaint.setStyle(Paint.Style.STROKE);
if (mDividerIndicator.size() == 0) {
circlePaint.setStrokeCap(Paint.Cap.ROUND);
circlePaint.setColor(mCircleGray);
canvas.drawArc(oval, CIRCLE_START_ANGLE, CIRCLE_SWEEP_ANGLE, false, circlePaint);
return;
}
circlePaint.setStrokeCap(Paint.Cap.ROUND);
drawCircleContent(canvas, mDividerIndicator.get(0), oval, perAngle, textRadius, path, textPaint, circlePaint);
int lastIndex = mDividerIndicator.size() - 1;
drawCircleContent(canvas, mDividerIndicator.get(lastIndex), oval, perAngle, textRadius, path, textPaint, circlePaint);
circlePaint.setStrokeCap(Paint.Cap.BUTT);
for (int i = 1; i < mDividerIndicator.size() - 1; i++) {
IndicatorItem item = mDividerIndicator.get(i);
drawCircleContent(canvas, item, oval, perAngle, textRadius, path, textPaint, circlePaint);
}
}
private void init() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
//View从API Level 11才加入setLayerType方法
//设置myView以软件渲染模式绘图
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setColor(mTextColor);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mFirstFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFirstFramePaint.setTextSize(mTextSize);
mFirstFramePaint.setAntiAlias(true);
mFirstFramePaint.setTextSize(mTextSize);
mFirstFramePaint.setColor(mTextColor);
mFirstFramePaint.setStyle(Paint.Style.FILL);
mFirstFramePaint.setTextAlign(Paint.Align.CENTER);
mSecondFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mSecondFramePaint.setTextSize(mTextSize);
mSecondFramePaint.setAntiAlias(true);
mSecondFramePaint.setTextSize(mTextSize);
mSecondFramePaint.setColor(mTextColor);
mSecondFramePaint.setStyle(Paint.Style.FILL);
mSecondFramePaint.setTextAlign(Paint.Align.CENTER);
mMiddleFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mMiddleFramePaint.setTextSize(mTextSize);
mMiddleFramePaint.setAntiAlias(true);
mMiddleFramePaint.setTextSize(mTextSize);
mMiddleFramePaint.setColor(mTextColor);
mMiddleFramePaint.setStyle(Paint.Style.FILL);
mMiddleFramePaint.setTextAlign(Paint.Align.CENTER);
mMaskFilterFirst = new BlurMaskFilter(3, BlurMaskFilter.Blur.NORMAL);
mMaskFilterSecond = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
mMaskFilterMiddle = new BlurMaskFilter(18, BlurMaskFilter.Blur.NORMAL);
mFirstFramePaint.setMaskFilter(mMaskFilterFirst);
mSecondFramePaint.setMaskFilter(mMaskFilterSecond);
mMiddleFramePaint.setMaskFilter(mMaskFilterMiddle);
testPaint = new Paint();
testPaint.setStyle(Paint.Style.FILL);
testPaint.setColor(Color.WHITE);
if (mFrameOffset <= 0) {
Paint.FontMetricsInt fmi = mTextPaint.getFontMetricsInt();
mFrameOffset = fmi.bottom - fmi.top;
}
}
public void chooseHeight(CharSequence text, int start, int end,
int spanstartv, int v,
Paint.FontMetricsInt fm);
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
return (int) paint.measureText(text.subSequence(start, end).toString());
}
@Override
public void chooseHeight(final CharSequence text, final int start, final int end,
final int spanstartv, final int v, final Paint.FontMetricsInt fm) {
// LogUtils.e(fm, sfm);
if (sfm == null) {
sfm = new Paint.FontMetricsInt();
sfm.top = fm.top;
sfm.ascent = fm.ascent;
sfm.descent = fm.descent;
sfm.bottom = fm.bottom;
sfm.leading = fm.leading;
} else {
fm.top = sfm.top;
fm.ascent = sfm.ascent;
fm.descent = sfm.descent;
fm.bottom = sfm.bottom;
fm.leading = sfm.leading;
}
int need = height - (v + fm.descent - fm.ascent - spanstartv);
if (need > 0) {
if (mVerticalAlignment == ALIGN_TOP) {
fm.descent += need;
} else if (mVerticalAlignment == ALIGN_CENTER) {
fm.descent += need / 2;
fm.ascent -= need / 2;
} else {
fm.ascent -= need;
}
}
need = height - (v + fm.bottom - fm.top - spanstartv);
if (need > 0) {
if (mVerticalAlignment == ALIGN_TOP) {
fm.bottom += need;
} else if (mVerticalAlignment == ALIGN_CENTER) {
fm.bottom += need / 2;
fm.top -= need / 2;
} else {
fm.top -= need;
}
}
if (end == ((Spanned) text).getSpanEnd(this)) {
sfm = null;
}
// LogUtils.e(fm, sfm);
}
public int getSize(@NonNull Rect outRect, @NonNull Paint paint, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, @Nullable Paint.FontMetricsInt fm) {
return getMinSize(outRect, paint, text, start, end, fm);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制背景
canvas.drawBitmap(backgroundBitmap, bitmapRect, mViewRect, mPaint);
//绘制提示文字透明背景
canvas.drawRoundRect(mRoundRect, 8, 8, mRectPaint);
//绘制底部提示文字 ( TextPiant 文字垂直居中实现 http://blog.csdn.net/hursing/article/details/18703599)
Paint.FontMetricsInt fontMetrics = mTipPaint.getFontMetricsInt();
float baseY = (mRoundRect.bottom + mRoundRect.top) / 2 - (fontMetrics.top + fontMetrics.bottom) / 2;
canvas.drawText(tips, screenW / 2, baseY, mTipPaint);
//绘制初始的11个气泡
for (int i = 0; i < players.length; i++) {
//绘制当前选中的球员
if (i == currentPos) {
if (players[i].isSetReal()) {
//绘制球员头像
canvas.drawBitmap(players[i].getBitmap(), positions[i].x - playW / 2,
positions[i].y - playW / 2, mPaint);
//绘制选中球员金色底座
canvas.drawBitmap(playSelectedBitmap, positions[i].x - goldW / 2,
positions[i].y - goldH / 2, mPaint);
//绘制球员姓名
canvas.drawText(players[i].getName(), positions[i].x,
positions[i].y + playW, mTextPaint);
} else {
canvas.drawBitmap(selectedBitmap, positions[i].x - playW / 2,
positions[i].y - playW / 2, mPaint);
}
} else {
canvas.drawBitmap(players[i].getBitmap(), positions[i].x - playW / 2,
positions[i].y - playW / 2, mPaint);
//设置了真实头像的气泡
if (players[i].isSetReal()) {
//绘制球员姓名
canvas.drawText(players[i].getName(), positions[i].x,
positions[i].y + playW, mTextPaint);
//绘制已设置正常图片球员背景
canvas.drawBitmap(playeBgBitmap, positions[i].x - grayW / 2,
positions[i].y + 200, mPaint);
}
}
}
}
public void chooseHeight(CharSequence text, int start, int end,
int spanstartv, int v,
Paint.FontMetricsInt fm, TextPaint paint) {
int size = mSize;
if (paint != null) {
size *= paint.density;
}
if (fm.bottom - fm.top < size) {
fm.top = fm.bottom - size;
fm.ascent = fm.ascent - size;
} else {
if (sProportion == 0) {
/*
* Calculate what fraction of the nominal ascent
* the height of a capital letter actually is,
* so that we won't reduce the ascent to less than
* that unless we absolutely have to.
*/
Paint p = new Paint();
p.setTextSize(100);
Rect r = new Rect();
p.getTextBounds("ABCDEFG", 0, 7, r);
sProportion = (r.top) / p.ascent();
}
int need = (int) Math.ceil(-fm.top * sProportion);
if (size - fm.descent >= need) {
/*
* It is safe to shrink the ascent this much.
*/
fm.top = fm.bottom - size;
fm.ascent = fm.descent - size;
} else if (size >= need) {
/*
* We can't show all the descent, but we can at least
* show all the ascent.
*/
fm.top = fm.ascent = -need;
fm.bottom = fm.descent = fm.top + size;
} else {
/*
* Show as much of the ascent as we can, and no descent.
*/
fm.top = fm.ascent = -size;
fm.bottom = fm.descent = 0;
}
}
}
/**
* Returns the width of a run of left-to-right text on a single line,
* considering style information in the text (e.g. even when text is an
* instance of {@link android.text.Spanned}, this method correctly measures
* the width of the text).
*
* @param paint the main {@link TextPaint} object; will not be modified
* @param workPaint the {@link TextPaint} object available for modification;
* will not necessarily be used
* @param text the text to measure
* @param start the index of the first character to start measuring
* @param end 1 beyond the index of the last character to measure
* @param fmi FontMetrics information; can be null
* @return The width of the text
*/
public static float measureText(TextPaint paint,
TextPaint workPaint,
CharSequence text, int start, int end,
Paint.FontMetricsInt fmi) {
return drawDirectionalRun(null, text, start, end,
Layout.DIR_LEFT_TO_RIGHT, false,
0, 0, 0, 0, fmi, paint, workPaint, true);
}