Android绘图篇(二)——绘制文本

前言:上一篇介绍了Canvas的基本操作,通过canvas来绘制各种图形:canvas基本操作,不过Canvas中还有两个比较复杂也比较重要的功能。分别是绘制文本(Text)和绘制路径(Path),今天就先看一下文本的绘制。先看下paint有哪些关于文本的设置:

paint.setTextAlign(Align.CENTER) :设置文字对齐方式
paint.setTextSize(12) :设置文字大小
paint.setFakeBoldText(true) :设置是否为粗体文字
paint.setUnderlineText(true) :设置下划线
paint.setTextSkewX((float) -0.25) :设置字体水平倾斜度,普通斜体字是 -0.25
paint.setStrikeThruText(true) :设置带有删除线效果
paint.setTextScaleX(2) :设置水平拉伸,高度不会变

好吧,这是针对绘制文本的一些设置。看下绘制绘制文本的api:

1drawText(char[] text, int index, int count, float x, float y,Paint paint
2drawText(String text, float x, float y, Paint paint)
3drawText(String text, int start, int end, float x, float y,Paint paint)
4drawText(CharSequence text, int start, int end, float x, float y,Paint paint)

这就是四个绘制Text的api。分别解释下每个api所传参数的意义:

1、分别传入字符数组、要绘制起始字符在数组中的index、绘制字符的个数,基线的x轴坐标、基线的y轴坐标、paint对象。
2、分别传入String字符串、基线的y轴坐标、paint对象。
3、分别传入String字符串、起始位置、结束位置、基线的y轴坐标、paint对象。比如“abcdefg”,start和end分别传入1和3,则会绘制bc。注意,不包含d,是半合区间[1,3)
4、和3一样,只不过第一个参数不同。

好了,于是我们愉快的执行第一个api,去绘制一个字符串:

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //设置画笔
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(ContextCompat.getColor(getContext(), R.color.colorAccent));
        paint.setTextSize(50);

        canvas.drawText("这是一个测试文本".toCharArray(), 1, 3, 0, 0, paint);
    }

于是看到如下效果:


在这里插入图片描述

是绘制了,但是为什么就绘制了一点点呢?要不是放大点,几乎看不见-。-为啥呢?

drawText()的基线

刚我们在介绍绘制文字的几个api时,不止一次提到了 基线这个词,这是啥玩意啊。来看一幅图:


在这里插入图片描述

图中的其它线暂且不管,我们可以看基线,图中标注baseline的位置。我们刚刚设置基线的位置是在(0,0)位置,文字的绘制都是基于baseline的,但不代表文字都在baseline的上方,有时候会绘制在baseline的下方,所以我们刚看到的效果就是绘制在基线下方的那一部分,如果我们调整下基线的y轴坐标:

canvas.drawText("这是一个测试文本".toCharArray(), 1, 3, 0, 100, paint);

效果如下:


在这里插入图片描述

这样文字就能看得到了。既然说到基线。我们在绘制文字的时候容易走进一个误区: 传入的坐标点是所绘制文字的左上角坐标。这是很容易犯的错误,实际上传入的是基线的坐标点。

paint.setTextAlign(Paint.Align align)

Align分别有三个值:

    public enum Align {
        LEFT
        CENTER
        RIGHT
    }

啥意思,先看下代码:

 paint.setTextAlign(Paint.Align.LEFT);
 canvas.drawText("这是一个测试文本".toCharArray(), 1, 3, 100, 100, paint);

 paint.setTextAlign(Paint.Align.CENTER);
 canvas.drawText("这是一个测试文本".toCharArray(), 1, 3, 100, 200, paint);

 paint.setTextAlign(Paint.Align.RIGHT);
 canvas.drawText("这是一个测试文本".toCharArray(), 1, 3, 100, 300, paint);

  paint.setColor(Color.parseColor("#00ff00"));
  paint.setStrokeWidth(5);
  canvas.drawLine(100,0,100,600,paint);

共绘制了三段文本,不同的是基线的位置不同,Align不同。为了区分,还绘制了一条绿线,用于标注基线所在的x坐标。分别看下效果就明白啥意思了:


在这里插入图片描述

如果指定Align为left,则文字绘制在基线x坐标的右侧;如果Align为center,则文字绘制在基线x坐标两侧;Align指定为right时,文字绘制在基线x坐标的左边。

FontMetrics

最开始的时候,我们放了一张图,我们只解释了其中的baseline(基线),还有top、ascent、descent、bottom四个值。都被封装在FontMetrics这个类中,分别表示如下含义:

  1. ascent:字符最高点到baseline的推荐距离。
  2. top:字符最高点到baseline的最大距离。
  3. descent:字符最低点到baseline的推荐距离。
  4. bottom:字符最低点到baseline的最大距离。

其实这几个值正常情况下用的比较少,正常情况下还是基线用的比较多,没有特殊需求的话,这几个值几乎用不到。不过这只是距离,如果要算出各个值的y轴坐标要怎么算呢?很简单,每个都和baseline的y轴左边有关系。

FontMetrics.ascent = ascent Y坐标 - baseline Y 坐标
FontMetrics.top = top Y 坐标 - baseline Y 坐标
FontMetrics.descent = descent Y 坐标 - baseline Y 坐标
FontMetrics.bottom = bottom Y 坐标 - baseline Y 坐标

有了这个公式,我们可以很轻松的发现FontMetrics.ascent和FontMetrics.top的值一定是负值,FontMetrics.descent和FontMetrics.bottom的值一定是正值。因为Android的坐标轴是从左到右、自上而下的。


在这里插入图片描述

FontMetrics对象的获取:

 Paint.FontMetrics fontMetrics = paint.getFontMetrics();
 float ascent = fontMetrics.ascent;
 float descent = fontMetrics.descent;
 float top = fontMetrics.top;
 float bottom = fontMetrics.bottom;

好吧 下面,下面来绘制一个文字,并绘制出文字所有的位置线:

       float baselineY = 100f;
       canvas.drawText("这是一个测试文本".toCharArray(), 1, 3, 100, baselineY, paint);

        //获取FontMetrics对象
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();

        //绘制top线
        paint.setColor(Color.GREEN);
        canvas.drawLine(0,baselineY+fontMetrics.top,600,baselineY+fontMetrics.top,paint);

        //绘制ascent线
        paint.setColor(Color.BLUE);
        canvas.drawLine(0,baselineY+fontMetrics.ascent,600,baselineY+fontMetrics.ascent,paint);

        //绘制descent线
        paint.setColor(Color.BLACK);
        canvas.drawLine(0,baselineY+fontMetrics.descent,600,baselineY+fontMetrics.descent,paint);

        //绘制bottom线
        paint.setColor(Color.YELLOW);
        canvas.drawLine(0,baselineY+fontMetrics.bottom,600,baselineY+fontMetrics.bottom,paint);
        
         //绘制基线
        paint.setColor(Color.RED);
        canvas.drawLine(0,baselineY,600,baselineY,paint);

好吧,看下效果:


在这里插入图片描述

红色是基线,其中top、ascent的差别还是挺大的,bottom和descent几乎重叠了。

测量文字宽度

paint还提供了一个measureText()方法用于测量文字所占的宽度。

 Log.e("TAG------",paint.measureText("这是一个测试文本")+"");

输出的结果如下:

2019-03-26 17:42:40.742 16367-16367/com.suning.ctspm E/TAG------: 400.0

这个宽度和你设置的文字大小有关系, paint.setTextSize()设置的值越大,宽度也越大。

获取最小矩形

paint中还封装了一个方法,用于获取文字的外切矩形,也叫最小矩形,方法如下。

/** 
 * 获取指定字符串所对应的最小矩形,以(0,0)点所在位置为基线 
 * @param text  要测量最小矩形的字符串 
 * @param start 要测量起始字符在字符串中的索引 
 * @param end   所要测量的字符的结束位置
 * @param bounds 用于接收测量结果 
 */  
public void getTextBounds(String text, int start, int end, Rect bounds);  

简单示例:

 Rect rect = new Rect();
 String text = "这是一个测试文本";
 paint.getTextBounds(text, 0, text.length(), rect);

于是你会发现获得的矩形:


在这里插入图片描述

咦,宽度怎么是396,刚我们上面打印的不是400么?原因如下:

measureText实际上是字体整体宽度,即左右带有一定的宽度。
getTextBounds获得的是字符串的最小矩形区域。

反正measureText()获取的宽度是在getTextBounds()左右坐标差的基础上加了一点点而已,正常想要获取文字的宽度用measureText()即可,高度也同理。

不过这个矩形还不能直接拿来绘制,原因是这个矩形的坐标是以(0,0)为文字的基线的,如果想要正确的绘制出文字的外切矩形,还需要加上文字的基线坐标,完整代码:

   Paint paint = new Paint();
   paint.setStyle(Paint.Style.FILL);
   paint.setColor(ContextCompat.getColor(getContext(), R.color.colorAccent));
   paint.setTextSize(50);

   String text = "这是一个测试文本";

   //基线的X轴坐标
   float baselineX = 100f;

   //基线的y轴坐标
   float baselineY = 100f;
   canvas.drawText(text, baselineX, baselineY, paint);


   Rect rect = new Rect();
   paint.setColor(Color.GREEN);
   paint.setStyle(Paint.Style.STROKE);
   paint.setStrokeWidth(3);
   //获取最小矩形并将矩形的信息,如left、top、right、bottom等存储到rect中
   paint.getTextBounds(text, 0, text.length(), rect);
   
   //绘制最小矩形,需要将最小矩形的left、top、right、bottom值加上基线所在的x坐标或y坐标
  canvas.drawRect(rect.left+baselineX,rect.top+baselineY,rect.right+baselineX,rect.bottom+baselineY,paint);

结果如下:


在这里插入图片描述

欧了,终于搞完了,下一篇准备介绍下Path和贝塞尔曲线相关的api,完~

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在Java中创建窗体并绘制文本,你可以使用Java的Swing组件库。以下是一个简单的示例代码,用于创建一个带有文本标签的窗体: ```java import javax.swing.*; public class MyWindow extends JFrame { public MyWindow() { JLabel label = new JLabel("Hello, World!"); add(label); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(300, 200); setVisible(true); } public static void main(String[] args) { new MyWindow(); } } ``` 在上面的代码中,我们使用JLabel组件创建了一个文本标签,并将其添加到窗体中。然后,我们设置了窗体的关闭操作、大小和可见性,并在main方法中创建了一个新的MyWindow对象来显示窗体。 如果你需要更复杂的文本绘制,可以使用Java的绘图API来手动绘制文本。以下是一个简单的示例代码,用于在窗体中手动绘制文本: ```java import java.awt.*; import javax.swing.*; public class MyWindow extends JFrame { public MyWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(300, 200); setVisible(true); } public void paint(Graphics g) { super.paint(g); g.drawString("Hello, World!", 100, 100); } public static void main(String[] args) { new MyWindow(); } } ``` 在上面的代码中,我们覆盖了paint方法来手动绘制文本。我们使用Graphics对象的drawString方法来绘制文本。在这个例子中,我们只是简单地绘制了一个字符串,但是你可以使用不同的字体、颜色和大小来自定义文本的外观。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值