[Android UI] graphics

来源:互联网 发布:网络变声电话 编辑:程序博客网 时间:2024/05/17 02:57

本文对Android graphics API 做些整理。

一、颜色 Color类

颜色由一个int型表示,共四个字节。从高位到低位四个字节分别为透明度、红色、绿色、蓝色。
相关API:

1.给定颜色获取相关属性

int alpha(int color)//返回给定颜色的透明度值,也就是高位第一个字节。   int red(int color)  //返回给定颜色的红色色值int green(int color) int blue(int color)

2.色调、饱和度、亮度。(下面三个返回值均为 0.0f~1.0f)

float hue(int color)//色调float saturation(int color)//饱和度float brightness(int color)//亮度

3.组成颜色

int rgb(int red, int green, int blue) //返回不透明的rgbint argb(int alpha, int red, int green, int blue)int parseColor(String colorString)//解析颜色,支持"#xxx...",预定义的几个字符串如"red"、"blue"等

4.颜色转化(hsb: hue色调,saturation饱和度,brghtness亮度
转换后alpha为0xff)

int HSBtoColor(float[] hsb)int HSBtoColor(float h, float s, float b) void RGBToHSV(int red, int green, int blue, float hsv[]) void colorToHSV(int color, float hsv[]) int HSVToColor(int alpha, float hsv[]) 

二、画笔 Paint类

参考文章:
Android Paint和Color类
反锯齿办法
android paint cap join 理解 图示

//设置颜色void setColor(int color);//抗锯齿void setAntiAlias(boolean aa);//设定是否使用图像抖动处理//会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰void setDither(boolean dither);//如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作//加快显示速度,本设置项依赖于dither和xfermode的设置 void setFilterBitmap(boolean filter)//当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度void setStrokeWidth(float width);//这个需要关闭硬件加速才有效果,这个是根据Alpha通道来计算的。setMaskFilter(MaskFilter maskfilter) //在图形下面设置阴影层,产生阴影效果radius为阴影的角度//dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色 setShadowLayer(float radius ,float dx,float dy,int color); 
//画笔的空心与实心,比如画一个圆圈,如果画笔为空心的//则画出来是空心圆,如果画笔是实心的,画出来是一个实心圆。void setStyle(Style style);

paint.setStyle(Paint.Style.STROKE);//画笔为空心的
android ui
paint.setStyle(Paint.Style.FILL); //画笔为实心的
android ui


//当画笔样式为STROKE或FILL_OR_STROKE时,用来控制我们的画笔在离开//画板时候留下的最后一点图形,竖线处即为画笔结束处void setStrokeCap(Cap cap);

这里写图片描述 BUTT
这里写图片描述 ROUND
这里写图片描述 SQUARE


paint.setStrokeJoin(Paint.Join.ROUND)

这里写图片描述 MITER
这里写图片描述 ROUND
这里写图片描述 BEVEL


setARGB(int a, int r, int g, int b);//设置画笔颜色paint.setARGB(128,255,0,0);canvas.drawCircle(centerX,centerY,200,paint);paint.setARGB(255,255,0,0);canvas.drawCircle(centerX+100,centerY,200,paint);

这里写图片描述


setcolorFilter 

参考
自定义控件其实很简单1/6
Paint、Canvas、Matrix使用讲解(一、Paint)

1.ColorMatrix
它定义了一个 4*5 的float[]类型的矩阵,矩阵中每一行表示 RGBA 中的一个参数。
颜色矩阵M是以一维数组m=[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]的方式进行存储的;
颜色矩阵:这里写图片描述
5x4 matrix for transforming the color+alpha components of a Bitmap. The matrix is stored in a single array, and its treated as follows: [ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ] When applied to a color [r, g, b, a], the resulting color is computed as (after clamping)
R’ = a*R + b*G + c*B + d*A + e;
G’ = f*R + g*G + h*B + i*A + j;
B’ = k*R + l*G + m*B + n*A + o;
A’ = p*R + q*G + r*B + s*A + t;

2.LightingColorFilter
LightingColorFilter(int mul, int add)//色彩倍增与偏移,这两个值都是16进制的色彩值0xAARRGGBB。最终颜色的计算方式为:(MUL_COLOR * 原色值 + ADD_COLOR )% 255

3.PorterDuffColorFilter
参考文章:
Porter-Duff 的由来

PorterDuffColorFilter(int color, PorterDuff.Mode mode)

其实就是用一个色值和要绘制的色值进行叠加,然后可以选择叠加的模式(PorterDuff.Mode),PorterDuff.Mode 以枚举的形式定义。
下面的表格中,S:源颜色,D:目标颜色,a:透明度。上面的构造函数参数color,对应下表中的 S,而下表中的D对应画笔要画上去的画布中的像素点的颜色。
这里写图片描述

PorterDuff的规则不仅用于图像的色彩混合,也用于图形混合。如果用于图像的色彩混合,个人理解,因为是在一个像素点的矩形区域进行,Src和Dst均为大小一样的矩形,像下图中的各种裁剪效果要么变成透明要么色彩叠加,裁剪效果是看不到的。

这里写图片描述

注意,这张图给人的第一感觉就是两个图形之间的集合之间的交集、并集等的处理,实际上完全不是这么一回事!
要根据上面表格中的计算公式来!

//PorterDuffXfermode  非常强大的图像混合器//参考上面的PorterDuff.Mode,注意不要用图形集合的方式去理解它//网上一堆例子抄来抄去,容易误导人,完全不对!按上面的计算公式来!setXfermode(Xfermode xfermode)

setPathEffect

参考文章 自定义控件其实很简单1/4

setShader

参考文章 Paint的setShader(Shader shader)


文本绘制

//模拟实现粗体文字,设置在小字体上效果会非常差  setFakeBoldText(boolean fakeBoldText);//设置该项为true,将有助于文本在LCD屏幕上的显示效果  setSubpixelText(boolean subpixelText);//设置绘制文字的对齐方向 setTextAlign(Paint.Align align); //设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果  setTextScaleX(float scaleX);//设置绘制文字的字号大小setTextSize(float textSize);  //设置斜体文字,skewX为倾斜弧度setTextSkewX(float skewX);  //设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等setTypeface(Typeface typeface);  //设置带有下划线的文字效果  setUnderlineText(boolean underlineText);//设置带有删除线的效果 setStrikeThruText(boolean strikeThruText);

三、画布 Canvas类

1.Rect、RectF
Rect 用left、top、right、bottom代表一个矩形区域。
RectF,也就是用 float类型表示的Rect区域。

2.画点

void drawPoints(float[] pts, int offset, int count, Paint paint)void drawPoints(float[] pts, Paint paint)void drawPoint(float x, float y, Paint paint);

3.画线

void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) void drawLines(float[] pts, int offset, int count, Paint paint);void drawLines(float[] pts, Paint paint) 

4.画矩形

void drawRect(RectF rect, Paint paint)void drawRect(Rect r, Paint paint)void drawRect(float left, float top, float right, float bottom, Paint paint)

5.画圆角矩形

drawRoundRect(RectF rect, float rx, float ry, Paint paint) 

这里写图片描述

6.画圆

void drawCircle(float cx, float cy, float radius, Paint paint) 

7.画椭圆

drawOval(RectF oval, Paint paint);//根据矩形区域的宽高画椭圆

8.画弧

void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)

宽高比为1:2的矩形区域画的圆弧,第四个参数代表是否使用中心点
这里写图片描述

9.画颜色

drawColor(int color)//把画布用颜色填满drawColor(int color, PorterDuff.Mode mode)

10.画路径

void drawPath(Path path, Paint paint) 

Path类,代表一路径,支持直线、二阶贝塞尔曲线、三阶贝塞尔曲线,非常强大。

1.线

void lineTo(float x, float y) rLineTo(float dx, float dy) 

2.贝塞尔曲线
参考 贝塞尔曲线 总结、 贝塞尔曲线

二阶贝塞尔曲线

quadTo(float x1, float y1, float x2, float y2)rQuadTo(float dx1, float dy1, float dx2, float dy2)

二阶贝塞尔曲线的用法,比较形象的例子参考 HTML5 canvas quadraticCurveTo() 方法
二次贝塞尔曲线需要两个点。第一个点是用于二次贝塞尔计算中的控制点,第二个点是曲线的结束点。曲线的开始点是当前路径中最后一个点。

这里写图片描述

这里写图片描述

这里写图片描述

原理:由 P0 至 P1 的连续点 Q0,描述一条线段。
由 P1 至 P2 的连续点 Q1,描述一条线段。
由 Q0 至 Q1 的连续点 B(t),描述一条二次贝塞尔曲线。
经验:P1-P0为曲线在P0处的切线。
3.三阶贝塞尔曲线
三阶贝塞尔曲线比二阶贝塞尔曲线多了一个控制点,参考HTML5 canvas bezierCurveTo() 方法

cubicTo(float x1, float y1, float x2, float y2,float x3, float y3) rCubicTo(float x1, float y1, float x2, float y2,float x3, float y3) 

这里写图片描述

这里写图片描述

这里写图片描述

通用公式:
这里写图片描述


11.弧形路径

void arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)//弧形路径void arcTo(RectF oval, float startAngle, float sweepAngle) 

这里写图片描述

12.画文字

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

13.在指定路径上画文字

void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint)

这里写图片描述

14.平移、旋转、缩放、错切

void translate(float dx, float dy)void rotate(float degrees)void scale(float sx, float sy);public final void scale(float sx, float sy, float px, float py) {    translate(px, py);    //先平移    scale(sx, sy);        //再缩放    translate(-px, -py);  //在缩放的基础上平移,不会回到刚开始平移之前那个点!}

————平移、旋转的例子—————-

int radius = 300;int textSize = 50;canvas.translate(centerX,centerY);//平移到中心canvas.save();canvas.drawCircle(0, 0, radius, paint);paint.setTextSize(textSize);paint.setTextAlign(Paint.Align.CENTER);canvas.rotate(30);for(int i = 1;i<=12;i++){    canvas.drawText(""+i,0,-radius+textSize,paint);canvas.drawLine(0,-radius+textSize+10,0,-radius+textSize*2,paint);canvas.rotate(30);}canvas.restore();

这里写图片描述

————平移、缩放、旋转的例子—————-

int radius = 300;int textSize = 50;canvas.translate(centerX,centerY);canvas.save();canvas.drawCircle(0, 0, radius, paint);paint.setTextSize(textSize);paint.setTextAlign(Paint.Align.CENTER);canvas.rotate(30);for(int i = 1;i<=12;i++){    canvas.drawText(""+i,0,-radius+textSize,paint);canvas.drawLine(0,-radius+textSize+10,0,-radius+textSize*2,paint);canvas.rotate(30);}canvas.restore();canvas.scale(0.5f,0.5f);canvas.rotate(30);for(int i = 1;i<=12;i++){    canvas.drawText(""+i,0,-radius+textSize,paint);canvas.drawLine(0,-radius+textSize+10,0,-radius+textSize*2,paint);canvas.rotate(30);}

这里写图片描述

————错切—————-

void skew(float sx, float sy);//理解两个参数sx为在x轴方向的tan值,sy为在y轴方向的tan值,错切后面积不变。

比如原图:
这里写图片描述

x轴方向错切45°:canvas.skew(1, 0);
这里写图片描述

y轴方向错切45°:canvas.skew(0, 1);
这里写图片描述


15.Matrix变换
这个就非常牛逼了,上面提到的什么平移、旋转、缩放、错切,本质上,就是把一个坐标(x0,y0)通过一个矩阵变换为(x1,y1)
而通过Matrix转换上面例子中的平移、缩放、旋转、错切统统不在话下。
比如把一个矩形旋转45°:

matrix.setRotate(45);canvas.concat(matrix);canvas.drawRect(rectF1, paint);

这里写图片描述

Matrix相关数学知识可以参考 Android Matrix理论与应用详解
Android matrix偏移(平移),旋转,缩放,倾斜的原理

Matrix相关的api:

void setTranslate(float dx, float dy)void setScale(float sx, float sy, float px, float py)   void setScale(float sx, float sy) void setRotate(float degrees, float px, float py)     void setRotate(float degrees) void setSinCos(float sinValue, float cosValue, float px, float py) void setSinCos(float sinValue, float cosValue)void setSkew(float kx, float ky, float px, float py)void setSkew(float kx, float ky)boolean setConcat(Matrix a, Matrix b)

注意,对于translate,scale,rotate,skew,concat均有preXXX和postXXX两种类型,而setXXX会清除掉preXXX和postXXX的设置。preXXX相当于矩阵的左乘法,postXXX相当于矩阵的右乘。

还有许多没列出来,以后继续研究。

16.画布状态的保存与恢复

//保存当前的matrix和clip到栈里int save()//同上,但是可以指定保留哪些操作int save(int saveFlags)//新建一层入栈,后续的draw操作都在这一层画,出栈的时候会把这一层的//东西画到前一层的上面。而这一层的区域大小,由RectF指定的bounds确定。int saveLayer(RectF bounds, Paint paint, int saveFlags)int saveLayer(float left, float top, float right, float bottom, Paint paint,int saveFlags) //新建一个带透明度的层,alpha值从0~255。int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int saveFlags) void restore()int getSaveCount()void restoreToCount(int saveCount)

例子:
在矩形区域上新建一个半透明的层,并画一个圆。

canvas.translate(centerX, centerY);//移动到中心RectF rectF1 = new RectF(0,0,200,200);canvas.drawRect(rectF1, paint);canvas.saveLayerAlpha(rectF1, 128, Canvas.ALL_SAVE_FLAG);Paint paint2 = new Paint();paint2.setColor(Color.RED);canvas.drawCircle(0,0,100,paint2);canvas.restore();

这里写图片描述

可以看见新建的层中,画的圆形的可视区域被限制在层的矩形区域bounds中了。

17.画布的裁剪
画布的裁剪就是把当前层裁剪出一块区域出来,之后的绘画只能在这块区域里画,区域范围外是不可视的。
比如裁剪一块矩形区域,然后画个圆:

canvas.drawColor(Color.BLACK);canvas.clipRect(100,100,200,200);canvas.drawCircle(100,100,100,paint)

这里写图片描述

可以看见圆形的可视区域被限制在裁剪区了。

裁剪的区域是非常灵活的,支持Path。
例如裁剪两个个三角形区域,然后在里面画个圆,可以看见圆形可视区域被限制在两个三角形的路径里了。

canvas.translate(centerX, centerX);Path path = new Path();path.lineTo(100,0);path.lineTo(50, 100);path.close();path.moveTo(50,100);path.lineTo(100,200);path.lineTo(0,200);path.close();canvas.clipPath(path);canvas.drawColor(Color.RED);canvas.drawCircle(50,100,50,paint);

这里写图片描述

裁剪Region
注意clipRegion与clipRect和clipPath不同,canvas的Matrix对clipRegion没有影响,clipRegion不会对Matrix进行转换。
看下面的例子:

canvas.scale(0.5f, 0.5f);canvas.save();canvas.clipRect(new Rect(100,100,200,200));//裁剪区域实际大小为50*50canvas.drawColor(Color.RED);canvas.restore();canvas.drawRect(new Rect(0,0,100,100), paint);//矩形实际大小为50*50canvas.clipRegion(new Region(new Rect(300,300,400,400)));//裁剪区域实际大小为100*100canvas.drawColor(Color.BLUE);

这里写图片描述

Region类
参考
Android 2D Graphics学习(二)、Canvas篇2、Canvas裁剪和Region、RegionIterator

Region类似PS中的选区,可以用矩形或者路径来构成选区。

 //构造方法 public Region();//创建一个空的区域 public Region(Region region); //拷贝一个region的范围 public Region(Rect r);  //创建一个矩形的区域 public Region(int left, int top, int right, int bottom); //创建一个矩形的区域/**一系列set方法,这些set方法,和上面构造方法形式差不多*/ public void setEmpty() { public boolean set(Region region);  public boolean set(Rect r) ; public boolean set(int left, int top, int right, int bottom) ; //往一个Region中添加一个Path只有这种方法, //参数clip代表这个整个Region的区域,在在里面裁剪出path范围的区域 public boolean setPath(Path path, Region clip) //用指定的Path和裁剪范围构建一个区域//几个判断方法public native boolean isEmpty();//判断该区域是否为空public native boolean isRect(); //是否是一个矩阵public native boolean isComplex();//是否是多个矩阵组合//一系列的getBound方法,返回一个Region的边界public Rect getBounds(); public boolean getBounds(Rect r); public Path getBoundaryPath(); public boolean getBoundaryPath(Path path); /**一系列的判断是否包含某点 和是否相交*/public native boolean contains(int x, int y);//是否包含某点public boolean quickContains(Rect r)   //是否包含某矩阵public native boolean quickContains(int left, int top, int right, int bottom) //是否没有包含某矩阵&nbsp;public boolean quickReject(Rect r) //是否没和该矩阵相交 public native boolean quickReject(int left, int top, int right, int bottom); //是否没和该矩阵相交 public native boolean quickReject(Region rgn);  //是否没和该矩阵相交/**几个平移变换的方法*/public void translate(int dx, int dy) public native void translate(int dx, int dy, Region dst);public void scale(float scale) //hidepublic native void scale(float scale, Region dst);//hide/**一系列组合的方法*/public final boolean union(Rect r) public boolean op(Rect r, Op op) {public boolean op(int left, int top, int right, int bottom, Op op) public boolean op(Region region, Op op) public boolean op(Rect rect, Region region, Op op) 选区有一系列的组合操作,假设用region1  去组合region2 public enum Op {        DIFFERENCE(0), //最终区域为region1 与 region2不同的区域        INTERSECT(1), // 最终区域为region1 与 region2相交的区域        UNION(2),      //最终区域为region1 与 region2组合一起的区域        XOR(3),        //最终区域为region1 与 region2相交之外的区域        REVERSE_DIFFERENCE(4), //最终区域为region2 与 region1不同的区域        REPLACE(5); //最终区域为为region2的区域 }
1 0
原创粉丝点击