第6章 CustomView Paint基本使用

一、硬件加速

概述:

GPU:Graphic Processing Uint,即“图形处理器”。与CPU不同,GPU是专门为处理图形任务而产生的芯片。

对Android来说,在API 11之前是没有GPU的概念的;在API 11之后,在程序集中加入了对GPU加速的支持;在API 14之后,硬件加速是默认开启的。我们可以显式地强制在进行图像计算时使用GPU而不是CPU。

软件绘制与硬件加速的区别:

在基于软件的绘制模型下,CPU主导绘图,视图按照两个步骤绘制:

● 让View层次结构失效。

● 绘制View层次结构。

在基于硬件加速的绘制模式下,GPU主导绘图,视频按照三个步骤绘制:

● 让View层次结构失效。

● 记录、更新显示列表。

● 绘制显示列表。

在GPU加速时,流程中多了一项“记录、更新显示列表”,表示在第一步View层次结构失效后,并不是直接开始逐层绘制的,而是首先把这些View的绘制函数作为绘制指令记录在一个显示列表中,然后再读取显示列表中的绘制指令,调用OpenGL的相关函数完成实际绘制。也就是说,在GPU加速时,实际上是使用OpenGL的相关函数完成绘制的。

所以,使用GPU加速的优点显而易见:硬件加速提高了Android系统显示和刷新的速度。

它的缺点也是显而易见的:

兼容性问题、内存消耗问题、电量消耗问题。

下图显示了一些特殊函数硬件加速开始支持的平台等级(叉号表示任何平台都不支持,不在列表中的默认从API 11开始支持):

禁用GPU硬件加速的方法:

如果应用程序运行在API 14以上版本上,而要用不用那些不支持硬件加速的函数,就只好禁用硬件加速了。

针对不同的类型,Android提供了不同的禁用方法,分为Application、Activity、Window、View 4个层级。

(1)在AndroidManifest.xml文件中为application标签添加如下属性,即可为整个应用程序开启/关闭硬件加速。

<application android:hardwareAccelerated="true" ...>

(2)在activity标签下使用hardwareAccelerated属性开启或关闭硬件加速。

<activity android:hardwareAccelerated="false" />

(3)在Window层级上使用如下代码开启硬件加速(Window层次上不支持关闭硬件加速)。

getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                     WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

(4)在View层级上关闭硬件加速(View层级上不支持开启硬件加速)。

setLayerType(View.LAYER_TYPE_SOFTWARE, null);
或使用android:layerType="software"来关闭硬件加速。
<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    ...
    android:layerType="software" />

二、文字

概述:

1.四线格与基线

    

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

2.canvas.drawText()函数

1)canvas.drawText()函数与基线

/**
* text:要绘制的文字
* x:绘制原点x坐标
* y:绘制原点y坐标
* paint:用来作画的画笔
*/
public void drawText(String text, float x, float y, Paint paint)

(x,y)坐标是文字所在矩形的左上角点位置?答:不是的!

比如要绘制“harvic's blog”这几个字,这个原点坐标是下图中基线开始处所标记出来的小点的位置。

2)示例

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        int baseLineX = 0;
        int baseLineY = 200;
        //画基线
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        canvas.drawLine(baseLineX, baseLineY, 3000, baseLineY, paint);
        //写文字
        paint.setColor(Color.GREEN);
        paint.setTextSize(120); //以px为单位
        canvas.drawText("harvic\'s blog", baseLineX, baseLineY, paint);
    }

首先把点(0,200)所在的这条横线画出来,然后利用canvas.drawText()函数以(0,200)为原点画出文字,最终效果如下图: 

  

3.paint.setTextAlign()函数

/**
* 其中Align的取值为Paint.Align.LEFT、Paint.Align.CENTER、Paint.Align.RIGHT
*/
Paint::setTextAlign(Align align);

4.注意

相对位置是根据所要绘制文字所在矩形来计算的。

比如,只写一个大写字母A,将其相对位置设置为Paint.Align.CENTER。

paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("A", baseLineX, baseLineY, paint);

绘图四线格与FontMetrics:

1.文字的绘图四线格

除了基线外,系统在绘制文字时还有4条线,分别是ascent、descent、top、bottom。

2.FontMetrics

FontMetrics概述

我们知道,基线的位置是在构造drawText()函数时由参数y来决定的,那么ascent、descent、top、bottom这些线的位置应该怎样计算出来呢?

Android给我们提供了一个类:FontMetrics,它里面有4个成员变量。

FontMetrics::ascent;
FontMetrics::descent;
FontMetrics::top;
FontMetrics::bottom;
● ascent = ascent线的y坐标 - baseline线的y坐标
● descent = descent线的y坐标 - baseline线的y坐标
● top = top线的y坐标 - baseline线的y坐标
● bottom = bottom线的y坐标 - baseline线的y坐标

获取FontMetrics对象:

Paint paint = new Paint();
Paint.FontMetrics fm = paint.getFontMetrics();// 得到的值类型为Float
Paint.FontMetrics fmInt = paint.getFontMetricsInt();// 得到的值类型为Int

 常用函数:

1.字符串所占区域的高度和宽度

1)高度

Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int topY = baseLineY - fm.top;
int bottomY = baseLineY - fm.bottom;
int height = bottomY - topY; // 所占区域的高度

2)宽度

int width = paint.measureText(String text);
使用示例:
Paint paint = new Paint();
paint.setTextSize(120);
int width = (int) paint.measureText("harvic\'s blog");

2.最小矩形

/**
* 获取指定字符串所对应的最小矩形,以(0,0)点所在位置为基线
* @param text 要测量最小矩形的字符串
* @param start 要测量起始字符在字符串中的索引
* @param end 所要测量的字符的长度
* @param bounds 接收测量结果
*/
public void getTextBounds(String text, int start, int end, Rect bounds);
示例:
String text = "harvic\'s blog";
Paint paint = new Paint();
paint.setTextSize(120); // 设置paint
Rect minRect = new Rect();
paint.getTextBounds(text, 0, text.length(), minRect);
Log.d("TAG", minRect.toShortString());
// 打印:D/TAG:[8,-90] [643,26]
// 即这个矩形左上角位置为(8,-90)、右下角位置为(634,26)

为什么左上角点的y坐标是一个负数?从代码中可以看到,我们并没有给getTextBounds()函数传递基线位置,那它就是以(0,0)点所在位置为基线来得到这个最小矩形的,所以这个最小矩形的位置就是以(0,0)点所在位置为基线的结果。

三、Paint常用函数

setARGB(int a, int r, int g, int b) // 给画笔设置颜色值
setAlpha(int a)// 利用A/R/G/B分开设置颜色
setStyle(Paint.Style style)// FILL/FILL_AND_STROKE/STROKE
setStrokeWidth(float width)// 设置画笔宽度
setAntiAlias(boolean aa)// 设置画笔是否抗锯齿
setStrokeMiter(float miter) // 设置画笔倾斜度
setPathEffect(PathEffect effect)// 设置路径样式
取值类型是所派生自PathEffect的子类:ComposePathEffect、CornerPathEffect、DashPathEffect、DiscretePathEffect、PathDashPathEffect、SumPathEffect.

setStrokeCap(Paint.Cap cap)
取值:
Cap.ROUND:圆形线帽
Cap.SQUARE:方形线帽
Cap.BUTT:无线帽
示例:
Paint paint = new Paint();
...// Paint各项初始化
paint.setStrokeCap(Paint.Cap.BUTT);
canvas.drawLine(100,200,400,200,paint);

各线帽样式效果如下:

setStrokeJoin(Paint.Join join)
设置路径的转角样式。
取值:
Join.MITER:结合处为锐角
Join.ROUNT:结合处为圆弧
Join.BEVEL:结合处为直线
示例:
Paint paint = new Paint();
...// Paint各项初始化
paint.setStrokeJoin(Paint.Join.MITER);
Path path = new Path();
path.moveTo(100, 100);
path.lineTo(450, 100);
path.lineTo(100, 300);
canvas.drawPath(path, paint);

各转角样式效果如下:

Android为了让彩色过渡不那么生硬,于是将相邻像素之间的颜色值进行“中和”以呈现一种更细腻的过渡色。

原: 现:

Android为我们提供了一个设置抗抖动效果的函数setDither(boolean dither)。

如果对抗抖动的图像进行放大,则会发现,它其实在很多相邻像素之间插入了一个“中间值”,如下图所示。

字体相关函数:

setTextSize(float textSize) // 设置文字大小
setFakeBoldText(boolean fakeBoldText) // 设置是否为粗体文字
setStrikeThruText(boolean strikeThruText) // 设置带有删除线效果
setTextAlign(Paint.Align align) // 设置开始绘图点位置
setTextScaleX(float scaleX) // 设置水平拉伸
setTextSkewX(float skewX) // 设置字体水平倾斜度。普通斜体字设置为-0.25,往右倾
setTextTypeface(Typeface typeface) // 设置字体样式
setLinearText(boolean linearText) // 设置是否打开线性文本标识

文本想要快速绘制出来,必然需要提前缓存在显存中。如果是长篇文章,则所需要的大小可想而知。可以通过setLinearText(true)函数告诉Android我们不需要这样的文本缓存。如果我们不用文本缓存,那么虽然能够省去一些内存,但这是以牺牲显示速度为代价的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itzyjr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值