Android笔记 自定义View(七):Canvas使用之绘制文字

目录

一、概述

二、drawText

1、四格线和基线

2、文字效果

3、文字对齐方式(setTextAlign)

4、字体相关(Typeface)

4.1、使用系统中的字体

4.2、使用自定义字体

5、文字截取

三、drawPosText 

四、drawTextOnPath 

五、drawTextRun

六、总结


一、概述

本篇主要介绍Canvas绘制文字的相关内容。Canvas绘制文字的相关方法,如下:

public void drawText(String text, float x, float y, @NonNull Paint paint);
public void drawText(char[] text, int index, int count, float x, float y, Paint paint) 
public void drawText(String text, int start, int end, float x, float y, Paint paint)
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint)

public void drawTextOnPath(char[] text, int index, int count, @NonNull Path path,
            float hOffset, float vOffset, Paint paint)
public void drawTextOnPath(String text, @NonNull Path path, float hOffset,
            float vOffset, Paint paint)

public void drawTextRun(char[] text, int index, int count, int contextIndex, 
            int contextCount, float x, float y, boolean isRtl, Paint paint)
public void drawTextRun(CharSequence text, int start, int end, int contextStart,
            int contextEnd, float x, float y, boolean isRtl, Paint paint)

public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint)
public void drawPosText(String text, float[] pos, Paint paint)

Canvas绘制文字的方法一共四分为四类:

  • drawText
  • drawPostText
  • drawTextOnPath
  • drawTextRun

下面我们详细说它们的使用。

二、drawText

先看下基本的使用。代码:

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setLayerType(LAYER_TYPE_SOFTWARE,null);
        // 初始化画笔
        initPaint();
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.DKGRAY);
        mPaint.setTextSize(80);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String text="Hello,安卓!";
        canvas.drawText(text, 0,0, mPaint);

    }

效果:

发现文字只显示下面一点点,这是为什么?

1、四格线和基线

其实这里的参数x,y并不是文字左上角顶点的位置,而是基线的起始位置。就像我们小时候学习写字母时,用的本子是四线格的,我们必须把字母按照规则写在四线格内。比如:

而canvas在利用drawText绘制文字时,也是有规则的,这个规则就是基线!我们先来看一下什么是基线:

在使用drawText绘制文字的时候会传入x,y两个参数,这两个参数不是指某一个点的坐标(当然为了好理解也可以作为一个点来看)。先看官方文档的解释:

@param x The x-coordinate of the origin of the text being drawn
@param y The y-coordinate of the baseline of the text being drawn

从上面的注释可以看出:x表示文本原点的x坐标;y表示文本基线的y坐标。为了理解方便将这两个坐标表示的点画出来。如图:

红点位置即是基线的起始位置,可见基线就是四线格中的第三条线。也就是说,只要基线的位置定了,那文字的位置必然是定了的!

代码:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String text="Hello,安卓!";
        canvas.drawText(text, 10,100, mPaint);
    }

效果:

其实除了基线之外,绘制文字时还有几条线要关注下,它们被封装在Paint.FontMetrics类中。如下:

    /**
     * Class that describes the various metrics for a font at a given text size.
     * Remember, Y values increase going down, so those values will be positive,
     * and values that measure distances going up will be negative. This class
     * is returned by getFontMetrics().
     */
    public static class FontMetrics {
        /**
         * The maximum distance above the baseline for the tallest glyph in
         * the font at a given text size.
         */
        public float   top;
        /**
         * The recommended distance above the baseline for singled spaced text.
         */
        public float   ascent;
        /**
         * The recommended distance below the baseline for singled spaced text.
         */
        public float   descent;
        /**
         * The maximum distance below the baseline for the lowest glyph in
         * the font at a given text size.
         */
        public float   bottom;
        /**
         * The recommended additional space to add between lines of text.
         */
        public float   leading;
    }

具体这几个变量代表的意思,大家可以自行百度

2、文字效果

绘制文字时,很多效果都可以通过Paint设置,如下:

/** 
* 普通设置 
*/  
//设置画笔颜色 
paint.setColor(Color.RED);   
//设置画笔宽度
paint.setStrokeWidth (5);
//指定是否使用抗锯齿功能,如果使用,会使绘图速度变慢
paint.setAntiAlias(true); 
//绘图样式,对于设文字和几何图形都有效
paint.setStyle(Paint.Style.FILL);
//设置文字对齐方式,取值:align.CENTER、align.LEFT或align.RIGHT
paint.setTextAlign(Align.CENTER);
//设置文字大小
paint.setTextSize(12);
 
/** 
* 样式设置
*/ 
//设置是否为粗体文字
paint.setFakeBoldText(true);
//设置下划线
paint.setUnderlineText(true);
//设置字体水平倾斜度,普通斜体字是-0.25
paint.setTextSkewX((float) -0.25);
//设置带有删除线效果
paint.setStrikeThruText(true);
//只会将水平方向拉伸,高度不会变
paint.setTextScaleX(2);

/** 
* 字体设置
*/ 
paint.setTypeface(typeface);

看下效果:

3、文字对齐方式(setTextAlign)

通过Paint.setTextAlign方法可以设置文字的对齐方式,共有三种:

  • Paint.Align.LEFT
  • Paint.Align.RIGHT
  • Paint.Align.CENTER

不过需要注意的是:这里的对齐方式是相对于基线的起始位置的。如下:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String text="Hello,安卓!";
        mPaint.setTextAlign(Paint.Align.LEFT);
        canvas.drawText(text, 400,100, mPaint);

        mPaint.setTextAlign(Paint.Align.RIGHT);
        canvas.drawText(text, 400,200, mPaint);

        mPaint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText(text, 400,300, mPaint);
    }

红点为基线的起始位置,一般默认的对齐方式是:Paint.Align.LEFT。

4、字体相关(Typeface)

Typeface是专门用来设置字体样式的,通过paint.setTypeface()来指定。可以指定系统中的字体样式,也可以指定自定义的样式文件中获取。要构建Typeface时,可以指定所用样式的正常体、斜体、粗体等,如果指定样式中,没有相关文字的样式就会用系统默认的样式来显示,一般默认是宋体。

创建Typeface:

 Typeface create(String familyName, int style) //直接通过指定字体名来加载系统中自带的文字样式
 Typeface create(Typeface family, int style)     //通过其它Typeface变量来构建文字样式
 Typeface createFromAsset(AssetManager mgr, String path) //通过从Asset中获取外部字体来显示字体样式
 Typeface createFromFile(String path)//直接从路径创建
 Typeface createFromFile(File path)//从外部路径来创建字体样式
 Typeface defaultFromStyle(int style)//创建默认字体

上面的各个参数都会用到Style变量,Style的枚举值如下:

Typeface.NORMAL  //正常体
Typeface.BOLD //粗体
Typeface.ITALIC //斜体
Typeface.BOLD_ITALIC //粗斜体

4.1、使用系统中的字体

从上面创建Typeface的所有函数中可知,使用系统中自带的字体有下面两种方式来构造Typeface:

 Typeface defaultFromStyle(int style)//创建默认字体:SANS_SERIF
 Typeface create(String familyName, int style) //直接通过指定字体名来加载系统中自带的文字样式

其实,第一个仅仅是使用系统默认的样式来绘制字体。第二个构造函数可以指定Android系统支持的三种字体:SERIF、MONOSPACE、SANS_SERIF。下面看下实现:

代码:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String text="Hello,安卓!";

        mPaint.setTypeface(Typeface.create(SERIF,Typeface.NORMAL));
        canvas.drawText(text, 10,100, mPaint);

        mPaint.setTypeface(Typeface.create(MONOSPACE,Typeface.NORMAL));
        canvas.drawText(text, 10,200, mPaint);

        mPaint.setTypeface(Typeface.create(SANS_SERIF,Typeface.NORMAL));
        canvas.drawText(text, 10,300, mPaint);
        
    }

效果图:

可以看出android系统默认的字体是SANS_SERIF。

4.2、使用自定义字体

自定义字体的话,我们就需要从外部字体文件加载我们所需要的字体的,有三个重载方法:

 Typeface createFromAsset(AssetManager mgr, String path) //通过从Asset中获取外部字体来显示字体样式
 Typeface createFromFile(String path)//直接从路径创建
 Typeface createFromFile(File path)//从外部路径来创建字体样式

看下具体使用:首先在Asset下建一个文件夹,命名为fonts,然后将字体文件hwxk.ttf 放入其中,使用上面的方法加载。

代码:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String text="Hello,安卓!";

        //根据路径得到Typeface
        Typeface typeface=Typeface.createFromAsset(mContext.getAssets(), "fonts/hwxk.ttf");
        mPaint.setTypeface(typeface);
        canvas.drawText(text, 10,100, mPaint);
    }

效果图:

5、文字截取

通过drawText另外三个重载方法可以实现文字的截取,如下

代码:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String text="Hello! 安卓";
        canvas.drawText(text,1,8,50,100,mPaint);
        canvas.drawText(text.toCharArray(),1,8,50,200,mPaint);
    }

效果图:

三、drawPosText 

这类重载方法可以分别指定每个文字的位置,截取一部分文字绘制。但是坑很多:

  • 必须指定所有字符位置,否则直接crash掉
  • 性能不佳,在大量使用的时候可能导致卡顿
  • 不支持emoji等特殊字符,不支持字形组合与分解

看下代码:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String text="Hello 安卓!";
        canvas.drawPosText(text.toCharArray(),0,9,new float[]{
                100,100,
                200,200,
                300,300,
                400,400,
                500,500,
                600,600,
                700,700,
                800,800,
                900,900,
        },mPaint);
    }

效果图:

四、drawTextOnPath 

根据方法名可以知道,这类重载方法根据路径绘制文字,代码实现:

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setLayerType(LAYER_TYPE_SOFTWARE,null);
        // 初始化画笔
        this.mContext=context;
        initPaint();
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.DKGRAY);
        mPaint.setTextSize(80);
        mPaint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String text="Hello 安卓!";
        Path paths = new Path();
        RectF rectF = new RectF(100, 100, 400, 600);
        paths.addArc(rectF, 180, 180);
        canvas.drawPath(paths, mPaint);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawTextOnPath(text, paths, 0, 0, mPaint);
    }

效果图:

这个方法后面在分析Path时,在详细说明。

五、drawTextRun

drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount, float x,         
            float y, boolean isRtl, Paint paint)
drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd, 
            float x, float y, boolean isRtl, Paint paint)

drawTextRun是在 API 23 新加入的方法。它和drawText一样都是绘制文字,但加入了两项额外的设置:上下文和文字方向。用于辅助一些文字结构比较特殊的语言的绘制(例如阿拉伯语根据它相邻的两个文字的不同会拥有不同的形状)。在绘制英文和汉语时没有发现contextIndex和contextCount参数的效果。另外contextIndex和contextCount参数要还有限制:contextIndex不能比index大;contextIndex+contextCount不能比index+count小。否则报错。简单看下它的使用:

代码:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String text="Hello 安卓!";
        canvas.drawTextRun(text.toCharArray(), 2, 6, 0, 8, 20, 100, true, mPaint);
        canvas.drawTextRun(text.toCharArray(), 2, 6, 1, 7, 20, 200, false, mPaint);
    }

效果图:

六、总结

上面简单分析了一些Canvas绘制文字的方法,其中需要注意的是绘制文字基线的位置并不是一般的左上角。还有涉及Path的相关内容后面在研究。

祝:工作顺利!

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android自定义View中的Canvas是一个绘图容器,可以在其上进行2D绘图操作。通过Canvas,我们可以绘制图形、文字、位图等。 要在自定义View使用Canvas,需要重写View的onDraw()方法,并在该方法中获取Canvas实例,然后进行绘制操作。 下面是一个简单的示例代码,展示如何在自定义View使用Canvas绘制一个矩形: ```java public class MyCustomView extends View { public MyCustomView(Context context) { super(context); } public MyCustomView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL); canvas.drawRect(100, 100, 300, 300, paint); } } ``` 在这个示例中,我们创建了一个名为MyCustomView自定义View,并重写了它的onDraw()方法。在该方法中,我们首先创建了一个Paint对象,设置了画笔的颜色为红色,并指定绘制的样式为填充。然后,使用Canvas的drawRect()方法绘制一个矩形,坐标为(100, 100)到(300, 300)。 当我们在布局文件中使用这个自定义View时,它会自动调用onDraw()方法进行绘制,从而在屏幕上显示出红色矩形。 需要注意的是,Canvas提供了许多其他绘制方法,如drawCircle()、drawText()等,可以根据需求选择合适的方法进行绘制操作。此外,还可以通过设置Paint对象的属性来实现不同的绘制效果,如线条宽度、字体大小等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值