使用canvas与Paint在View中居中绘制文字

本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接

我们在自定义View中有的时候会想自己绘制文字,自己绘制文字的时候,我们通常希望把文字精确定位,文字居中(水平、垂直)是普遍的需求,所以这里就以文字居中为例,看一下android中的文字应该如何绘制,它与Java又有什么区别。

先来看看我们的目标,见下图

上图是我打开了“显示布局边界”后截的图,所有会有好多框框。

仔细观察上图文字区域,我们会发现文字区域中有5条颜色不同的线。按着从上到下的顺序,他们的名字分别是:

top:浅灰色

ascent:黄色

baseline:红色

descent:蓝色

bottom:绿色

这5条线到底是什么?android开发文档中已经进行了解释。

top The maximum distance above the baseline for the tallest glyph in the font at a given text size.
ascent The recommended distance above the baseline for singled spaced text.
leading The recommended additional space to add between lines of text.
descent The recommended distance below the baseline for singled spaced text.
bottom The maximum distance below the baseline for the lowest glyph in the font at a given text size.

我们先稍微跑一下题

如果你尝试过将两个TextView上下排列,没有margin和padding,那么你一定会发现,两个TextView文字之间依然是有空隙的。首先我们需要设置includeFontPadding为false!但是依然有空隙,这时的空隙就是由top与ascent之间的空隙和bottom与descent直接的空隙造成的了。

那5条线的位置是由使用的字体和字号决定的。Paint提供了获取上面5条线位置的方法。

一般情况下,我们使用的字符是在ascent与descent之间的,所以我们让ascent与descent之间的部分相对我们的View居中即可。

以baseline为基准,向上为负,向下为正。ascent为负数,descent为正数。

Canvas中的drawText中的总坐标是baseline,所以我们这里要先算出baseline的位置才行。

baseline = (mHeight - (mFontMetricsInt.descent - mFontMetricsInt.ascent)) / 2 - mFontMetricsInt.ascent

使得ascent到View的是上边距与descent到View下边距距离一致即可,此段距离加上ascent的绝对值(-ascent)即为baseline的位置

@Override
public void onDraw(Canvas canvas) {
    int x;
    if (mPaint.getTextAlign() == Paint.Align.LEFT) { //左
        x = mWidth / 2 - (int) (mStringWidth / 2);
    } else if (mPaint.getTextAlign() == Paint.Align.CENTER) { //中
        x = mWidth / 2;
    } else { //右
        x = mWidth / 2 + (int) (mStringWidth / 2);
    }

    int xFrom = mWidth / 2 - (int) (mStringWidth / 2);
    int xTo = mWidth / 2 + (int) (mStringWidth / 2);

    // baseline = (mHeight - (mFontMetricsInt.descent - mFontMetricsInt.ascent)) / 2 - mFontMetricsInt.ascent
    // baseline = (mHeight - mFontMetricsInt.ascent - mFontMetricsInt.descent) / 2
    int y = (mHeight - mFontMetricsInt.ascent - mFontMetricsInt.descent) / 2;
    Log.d(TAG, "ascent: " + mFontMetricsInt.ascent);
    Log.d(TAG, "descent: " + mFontMetricsInt.descent);
    Log.d(TAG, "top: " + mFontMetricsInt.top);
    Log.d(TAG, "bottom: " + mFontMetricsInt.bottom);
    Log.d(TAG, "baseline: " + y);

    // baseline
    mPaint.setColor(Color.RED);
    canvas.drawLine(xFrom, y, xTo, y, mPaint);
    // ascent
    mPaint.setColor(Color.YELLOW);
    canvas.drawLine(xFrom, y + mFontMetricsInt.ascent, xTo, y + mFontMetricsInt.ascent, mPaint);
    // descent
    mPaint.setColor(Color.BLUE);
    canvas.drawLine(xFrom, y + mFontMetricsInt.descent, xTo, y + mFontMetricsInt.descent, mPaint);
    // top
    mPaint.setColor(Color.LTGRAY);
    canvas.drawLine(xFrom, y + mFontMetricsInt.top, xTo, y + mFontMetricsInt.top, mPaint);
    // bottom
    mPaint.setColor(Color.GREEN);
    canvas.drawLine(xFrom, y + mFontMetricsInt.bottom, xTo, y + mFontMetricsInt.bottom, mPaint);

    mPaint.setColor(Color.BLACK);
    canvas.drawText(TEST_STRING, x, y, mPaint);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mWidth = w;
    mHeight = h;
}

private int mWidth;
private int mHeight;
private float mStringWidth;

private float measureText() {
    mStringWidth = mPaint.measureText(TEST_STRING);
    return mStringWidth;
}

垂直居中解决了,水平居中就容易了。因为……可以在Paint中直接设置。

mPaint.setTextAlign(Paint.Align.CENTER);

当然,这里的对其方式只有左中右,即使这里没有设置居中,我们也是可以手动居中文字的。

int x;
if (mPaint.getTextAlign() == Paint.Align.LEFT) { //左
    x = mWidth / 2 - (int) (mStringWidth / 2);
} else if (mPaint.getTextAlign() == Paint.Align.CENTER) { //中
    x = mWidth / 2;
} else { //右
    x = mWidth / 2 + (int) (mStringWidth / 2);
}

横纵坐标计算好了之后,我们就可以drawText了。

canvas.drawText(TEST_STRING, x, y, mPaint);

至此,问题全部解决,我们知道文字上面的那几条线的位置,就能随意放置我们的文字了。

绘制数字的时候,1明显比4瘦,但是我们可能会得到他们宽度相同的结果,也就没有办法“真正的居中”了。

最后我们来看看Java中的字体和Android的区别。

Java中字体的概念在这里:Font Concepts。可以看到,这里并没有Android中的top和bottom的概念。

在维基百科中也有baseline相关解释。这里也是没有提到Android中的top与bottom的概念

转贴请保留以下链接

本人blog地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-24 09:19:24

使用canvas与Paint在View中居中绘制文字的相关文章

IOS开发 图形绘制,绘制线条,矩形,和垂直和居中绘制文字

概述 吐槽下IOS下 的图形绘图,代码冗长,不得不自己重新封装方法.整理形成本文. 绘制线 // 绘制直线 + (void)toDrawLineFromX:(CGFloat)x1 Y:(CGFloat)y1 toX:(CGFloat)x2 toY:(CGFloat)y2 context:(CGContextRef)con{ CGContextMoveToPoint(con, x1, y1); CGContextAddLineToPoint(con, x2, y2); CGContextSetLi

View 、Canvas、Paint

View:视图,每一个view都有一个用于绘图的画布,这个画布可以任意的扩展.在android中,任何一个view都需要重写onDraw()方法来实现. Canvas:画布,利用Canvas可画出(点.直线.圆.椭圆.矩形.文字) Paint:画笔 代表了Canvas上的画笔,画刷.颜料等. 如果paint是笔,那么canvas是笔记本,view是桌子. 绘制点.圆等实例:(先创建一个类来继承view类,然后重写onDraw方法,然后在活动中加载) public class MyView ext

【Android】21.2 Canvas和Paint

分类:C#.Android.VS2015: 创建日期:2016-03-19 一.Canvas对象简介 画布(Canvas对象)是与System.Drawing或iOS核心图形等传统框架非常类似的另一种图形图像绘制技术,该对象提供了创建2D图形的最大控制,利用它可解决难以处理画板资源的情况.例如,绘制自定义滑块控件的外观等. 可以把Canvas理解成系统提供给我们的一块内存区域(但实际上它只是一套绘图API,真正的内存是下面的Bitmap),而且它还提供了一整套对这个内存区域进行操作的方法,所有的

使用XCB编写X Window程序(04):在窗口中绘制文字

在前面的几节中,我展示了使用XCB创建窗口.在窗口中画图以及捕获并处理事件.在这一篇中,我将展示在窗口中绘制文字.绘制文字当然离不开字体,所以我还会简单地探讨一下X Server的核心字体系统.老规矩,先上代码和运行效果图,代码如下: 1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <inttypes.h> 5 #include <xcb/xcb.h

Android查缺补漏(View篇)--自定义View利器Canvas和Paint详解

上篇文章介绍了自定义View的创建流程,从宏观上给出了一个自定义View的创建步骤,本篇是上一篇文章的延续,介绍了自定义View中两个必不可少的工具Canvas和Paint,从细节上更进一步的讲解自定义View的详细绘制方法.如果把自定义View比作盖一座房子,那么上篇文章就相当于教会了我们怎么一步步的搭建房子的骨架,而本篇文章将要教会我们的是为房子的骨架添砖加瓦直至成型,甚至是怎么装修. Canvas 为了后文更为方便的讲解Canvas的常用方法的使用,我们先来做一些准备工作,创建一个自定义V

Android中android.graphics下面的绘制图形类Canvas,Paint,Bitmap,Drawable

1.概念区别: 很多网友刚刚开始学习Android平台,对于Drawable.Bitmap.Canvas和Paint它们之间的概念不是很清楚, 其实它们除了Drawable外早在Sun的J2ME中就已经出现了,但是在Android平台中,Bitmap.Canvas相关的都有所变化. 首先让我们理解下Android平台中的显示类是View,但是还提供了底层图形类android.graphics,今天所说的这些均为graphics底层图形接口. Bitmap - 称作位图,一般位图的文件格式后缀为b

android游戏开发中图形绘制:Canvas和Paint的使用

android游戏开发中,使用android.graphics中的类来绘制2D向量图和文字. 一 画布Canvas 在Android中的绘图应该继承View组件,并重写它的onDraw(Canvas canvas)方法. Canvas代表指定View上的画布,常用方法如图: 二 画刷Paint Paint代表Canvas上的画刷,主要用于绘制风格,包括画刷颜色.画刷笔触粗细.填充风格等. 大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关. 常用方法如图: 三 路径Path Path表示

View、Canvas、Paint

View:课桌 Canvas:笔记本 Paint:手中的笔 canvas.save();  //保存当前图形的一个可以剪辑的状态 paint.setColor(Color.parseColor("#33ff88"));//设置颜色 paint.setColor(Color.rgb(33,65,88));//设置颜色 canva.restore(); //释放资源 来自为知笔记(Wiz)

Android使用学习之画图(Canvas,Paint)与手势感应及其应用(乒乓球小游戏)

作为一个没有学习Android的菜鸟,近期一直在工作之外努力地学习的Android的使用. 这周看了下Android的画图.主要是Canvas,Paint等,感觉须要实践下.下午正好有空,就想整一个乒乓球的游戏,算是巩固学的知识. 首先,须要了解下Android的画图须要掌握的经常使用类.包含Canvas,就像一个画板一样,全部的东西都是在其上画的.Paint就是画笔.用其能够画各种基本图形和文字.       Canvas和Paint经常使用的方法就不列举了,这种东西网上到处是.有了这两个东西