`
su1216
  • 浏览: 670984 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Group-logo
深入入门正则表达式(jav...
浏览量:71916
E60283d7-4822-3dfb-9de4-f2377e30189c
android手机的安全问...
浏览量:128763
社区版块
存档分类
最新评论

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

阅读更多

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

 

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

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

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

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

top:浅灰色

ascent:黄色

descent:蓝色

bottom:绿色

 

这4条线到底是什么?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.
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的位置

private void init() {
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setStrokeWidth(3);
    mPaint.setTextSize(60);
    mPaint.setTextAlign(Paint.Align.CENTER);
    mPaint.setStyle(Paint.Style.STROKE);
    mFontMetricsInt = mPaint.getFontMetricsInt();
}

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

注意:上面的那几条线的位置和字体是有关的,比如,当你使用“方正姚体”的时候,会发现top和ascent重合了

private void init() {
    mTf = Typeface.createFromAsset(mContext.getAssets(), "fzyt.ttf");
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setTypeface(mTf);
    mPaint.setStrokeWidth(3);
    mPaint.setTextSize(60);
    mPaint.setTextAlign(Paint.Align.CENTER);
    mPaint.setStyle(Paint.Style.STROKE);  // 画空心矩形
    mFontMetricsInt = mPaint.getFontMetricsInt();
    Log.d(TAG, "measureText: " + measureText());
}

垂直居中解决了,水平居中就容易了。因为……可以在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瘦,但是我们可能会得到他们宽度相同的结果,也就没有办法“真正的居中”了。

附上layout文件,如果你设置了padding,记得把padding也计算进去。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
        android:background="#FFFFFF">
    <com.example.TextTest.TextView
            android:layout_width="250dip"
            android:layout_height="100dip"
            android:layout_marginTop="10dip"
            android:layout_marginBottom="20dip"
            android:layout_marginLeft="10dip"
            android:layout_marginRight="20dip"/>
</LinearLayout>

 

 

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

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

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

 

 

转贴请保留以下链接

本人blog地址

http://su1216.iteye.com/

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

分享到:
评论

相关推荐

    Android 自定义View绘制居中文本

    3. **绘制文本**:在`onDraw()`方法中,使用`canvas.drawText()`方法来绘制文本。传入计算好的坐标和要显示的文本,即可实现居中效果。 ```java @Override protected void onDraw(Canvas canvas) { super.onDraw...

    Android TextView的图片和文字居中探索

    接着,我们在`onDraw()`方法中分别绘制文字和图片,应用偏移量使得它们都处于居中位置。 当然,这只是一个基础的实现,实际项目中可能需要处理更多复杂情况,例如文字有多行、图片大小不固定等。在这种情况下,可能...

    Android Canvas的drawText()与文字居中方案详解

    在Android中,我们可以使用`setTextAlign()`方法来改变文字的对齐方式,包括左对齐(`Paint.Align.LEFT`)、居中对齐(`Paint.Align.CENTER`)和右对齐(`Paint.Align.RIGHT`)。不同的对齐方式会影响`x`参数的实际...

    Android中Paint类的定义与使用简介.pdf

    Paint类是继承自java.lang.Object的,它主要用于描述在Android视图(View)上绘制图形时的各种样式属性。例如,你可以使用Paint来设定线条的颜色、宽度、透明度、抗锯齿效果、填充模式等。通过Paint,开发者可以定制出...

    自定义view实现图文 测量文字尺寸

    现在,我们可以开始在`onDraw()`方法中绘制图片和文字了。首先,绘制图片,然后根据指定的对齐方式计算文字的起始位置。例如,右对齐意味着文字应该在图片右边开始,左对齐则相反,居中则需要找到它们之间的中点: ...

    Android中搜索图标和文字居中的EditText实例

    在本例中,我们使用Paint来绘制搜索文字,设置文字的颜色、大小和样式。 知识点4:使用Canvas绘制图形 在Android中,Canvas是用于绘制图形的工具。在本例中,我们使用Canvas来绘制搜索图标,通过translate和draw...

    Android开发之图形图像与动画(一)Paint和Canvas类学习

    在实际开发中,我们通常会在自定义的View类中重写`onDraw()`方法,利用Canvas和Paint来绘制图形。例如,以下是一个简单的自定义View的示例: ```java public class DrawView extends View { public DrawView...

    android自定义View探索4(文字跑马灯)

    在Android开发中,自定义View是一项重要的技能,它允许开发者根据需求创建独特的用户界面元素。本篇文章将深入探讨如何实现“文字跑马灯”效果,这是Android应用中常见的一种动态展示文本的方式,常用于滚动通知或者...

    自定义View随机生成数字验证码

    我们可以使用Canvas对象来绘制文字,例如: ```java @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLACK);...

    自定义view图片圆角

    然后在布局文件中使用: ```xml android:layout_width="wrap_content" android:layout_height="wrap_content" app:cornerRadius="16dp" android:src="@drawable/your_image" /&gt; ``` 这样,我们就创建了一个...

    Android画图学习总结(五)——Paint_玉树临疯_ 京华志

    2. 在onDraw方法中使用Canvas的drawText方法绘制文本: ```java @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawText("Hello Android", getWidth() / 2, getHeight() / 2...

    Android拆轮子系列之写验证码控件的方法

    本篇文章将详细介绍如何在Android中编写一个验证码控件,涉及到的主要知识点包括Canvas和Paint的使用以及View的基本操作。 Canvas是Android图形库的核心部分,用于在Bitmap上进行绘制。我们可以使用Canvas提供的...

    android画波浪线,老师批改作业效果

    在Android开发中,有时我们需要实现一些特殊的视觉效果,比如...5. 在布局文件中使用自定义View。 通过这些步骤,你可以在Android应用中实现具有波浪线效果的自定义View,营造出“老师批改作业”的独特视觉体验。

    Android自定义View带进度的圆形进度条

    为了显示百分比,我们可以在`onDraw()`中添加文字绘制。使用`Paint`对象设置字体大小、颜色和对齐方式,然后计算文本在圆上的位置,确保其居中显示。 ```java private void drawPercentageText(Canvas canvas, ...

    安卓Andriod源码——简单用canvas实现一个圆锥漏斗,按照比例分成不同颜色显示。用来做统计。.zip

    在Android开发中,Canvas是用于在屏幕上绘制图形的重要工具,它是Android SDK中的一个核心类。本项目通过Canvas实现了一个圆锥漏斗图,这是一种常见的数据可视化方式,常用于统计数据并展示不同部分的比例关系。下面...

    Android中绘制常见的几何图形的代码清单.pdf

    在`Rectangle`类中,除了获取宽度和高度外,我们还可以使用`canvas.drawRect()`方法来绘制矩形。这个方法需要左上角和右下角的坐标,以及`Paint`对象。在这里,矩形的宽高通常设定为屏幕宽度和高度减去一些偏移值,...

    android 画圆

    我们可以在View的onDraw()方法中使用Canvas来绘制图形。此外,Paint对象用于设置颜色、样式等绘画属性。 为了动态画圆,我们需要一个自定义View,例如命名为CircleProgressView。在这个View中,我们将定义一个圆形...

    Android EditText搜索框实现图标居中

    接着,我们使用Paint对象来绘制图标,并将其添加到Canvas对象中。 iv. 图标居中 要实现图标居中的效果,我们需要计算图标的位置。这里,我们使用Paint对象的measureText方法来获取文本的宽度,然后计算图标的水平...

    android 定制view

    这样,我们就可以在布局XML中使用这个自定义View,并通过代码设置数字: ```xml android:id="@+id/custom_number_view" android:layout_width="wrap_content" android:layout_height="wrap_content" /&gt; ``` ``...

Global site tag (gtag.js) - Google Analytics