一、硬件加速
概述:
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我们不需要这样的文本缓存。如果我们不用文本缓存,那么虽然能够省去一些内存,但这是以牺牲显示速度为代价的。