05、Android绘图机制
一、绘图基础
1.1、Canvas和Paint
系统提供Canvas对象来提供绘图方法,其中Paint常见的属性如下:
mPaint.setAntiAlias() // 设置画笔的锯齿效果 mPaint.setColor() // 设置画笔的颜色 mPaint.setARGB() // 设置画笔的A、R、G、B值 mPaint.setAlpha() // 设置画笔的Alpha值 mPaint.setTextSize() // 设置字体的尺寸 mPaint.setStyle() // 设置画笔的风格(空心或实心) mPaint.setStrokeWidth() // 设置空心边框的宽度
1、基本绘制
// 1、绘制点 canvas.drawPoint(x, y, paint);
// 2、绘制直线 canvas.drawLine(startX, startY, stopX, stopY, paint);
// 3、绘制多条直线 float[] pts = { startX1, startY1, endX1, endY1, ...... startXn, startYn, endXn, endYn}; canvas.drawLines(pts, paint);
// 4、绘制矩形 canvas.drawRect(left, top, right, bottom, paint);
// 5、绘制圆角矩形 canvas.drawRoundRect(left, top, right, bottom, rx, ry, paint);
// 6、绘制圆 canvas.drawCircle(cx, cy, radius, paint);
// 7、绘制弧形,这里需要注意绘制弧线和扇形的区分就是倒数第二个参数useCenter的值,true或false mPaint.setStyle(Paint.Style.STROKE); canvas.drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
// 8、绘制椭圆 canvas.drawOval(left, top, right, bottom, paint);
// 9、绘制文本 canvas.drawText(text, x, y, paint);
// 10、在指定位置绘制文本 canvas.drawPosText(text, new float[]{ X1, Y1, ...... Xn, Yn}, paint);
// 11、绘制路径 Path path = new Path(); path.moveTo(50, 50); path.lineTo(100, 100); path.lineTo(100, 300); canvas.drawPath(path, mPaint);
1.2、Shape绘图
1、xml控件配置属性
android:background="@drawable/shape"
3、shape制作圆角
<Button android:layout_width="160dp" android:layout_height="wrap_content" android:background="@drawable/button_shape" android:text="圆角按钮" />
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="#fff"/> <padding android:top="10px" android:bottom="10px"/> <corners android:radius="16px"/> <stroke android:width="1px" android:color="#000"/> </shape>
4、shape制作虚线
没有dashGap属性则为实线
<View android:layout_width="match_parent" android:layout_height="5px" android:layout_marginTop="10dp" android:background="@drawable/line_shape" />
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line" > <stroke android:dashGap="3dp" android:dashWidth="8dp" android:width="1dp" android:color="#63a219"/> <size android:height="1dp"/> </shape>
5、shape制作渐变
<View android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginTop="10dp" android:background="@drawable/gra_shape" />
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <gradient android:angle="270.0" android:startColor="#000000" android:endColor="#ffffff"/> </shape>
1.3、Layer
Layer是在Photoshop中非常的功能。在Android中同样可以通过Layer来实现类似Photoshop中图层的概念。
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <!-- 图片 1--> <item android:drawable="@drawable/ic_launcher"></item> <!-- 图片 2 --> <item android:drawable="@drawable/ic_launcher" android:left="10.0dip" android:top="10.0dip" android:right="10.0dip" android:bottom="10.0dip"> </item> </layer-list>
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/a"></item> <item android:drawable="@drawable/b"></item> </layer-list>
引用:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/add_layer" />
+
=
1.4、Selector
1、创建xml文件
创建xml文件,位置:drawable/xxx.xml.同目录下记得放相关图片
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 没有焦点时的背景图片 --> <item android:drawable="@drawable/handle_normal" android:state_enabled="true" android:state_window_focused="false"/> <!-- 触摸模式按下时的背景图片 --> <item android:drawable="@drawable/handle_pressed" android:state_pressed="true"/> <item android:drawable="@drawable/handle_focused" android:state_enabled="true" android:state_focused="true"/> <item android:drawable="@drawable/handle_normal" android:state_enabled="true"/> <!-- 获得焦点时的图片背景 --> <item android:drawable="@drawable/handle_focused" android:state_focused="true"/> <!-- android:state_selected是选中 android:state_focused是获得焦点 android:state_pressed是点击 android:state_enabled是设置是否响应事件,指所有事件 --> </selector>
2、使用xml文件
1.方法一:在listview中配置android:listSelector="@drawable/xxx或在listview的item中添加属性android:background="@drawable/xxx"
2.方法二:
Drawable drawable = getResources().getDrawable(R.drawable.xxx);
ListView.setSelector(drawable);
但是这样会出现列表有时候为黑的情况,需要加上:android:cacheColorHint="@android:color/transparent"使其透明。
3、Shape选择器
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <item android:state_pressed="true"> <shape android:shape="rectangle"> <!-- 填充的颜色 --> <solid android:color="#33444444"/> <!-- 设置按钮的四个角为弧形 --> <corners android:radius="5dp"/> <!-- padding:Button里面的文字与Button的边界的间隔 --> <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp"/> </shape> </item> <item android:state_pressed="false"> <shape android:shape="rectangle"> <!-- 填充的颜色 --> <solid android:color="#FFFFFF"/> <!-- 设置按钮的四个角为弧形 --> <corners android:radius="5dp"/> <!-- padding:Button里面的文字与Button边界间隔 --> <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp"/> </shape> </item> </selector>
使用方法:
android:focusable="true"
android:background="@drawable/shape_select"
4、颜色选择器
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"><color android:color="#999999" /></item> <item android:state_pressed="false"><color android:color="#ffffff" /></item> </selector>
二、绘图进阶
1.1、Canvas
Canvas作为绘制图像的直接对象,提供以下几个非常有用的方法:
- Canvas.save(): 保存画布,将之前所有已经绘制的图像保存起来,让后续操作在新的图层上操作。
- Canvas.restore() 合并图层操作,它的作用是将save()之后绘制的所有图像与save()之前的图像进行合并。
- Canvas.translate() 和 Canvas.rotate():画布的坐标系的翻转和偏移。
1、绘制仪表盘实例
- 仪表盘 --- 外面的大圆盘
- 刻度线 --- 包含四个长的刻度线和其他短的刻度线
- 刻度值 --- 包含长刻度线对应的大的刻度值和其他小的刻度值
- 指针 --- 中间的指针,一粗一细两根指针
public class KeDuPanView extends View { private int mWidth; private int mHeight; public KeDuPanView(Context context) { this(context, null); } public KeDuPanView(Context context, AttributeSet attrs) { super(context, attrs); WindowManager wManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mWidth = wManager.getDefaultDisplay().getWidth(); mHeight = wManager.getDefaultDisplay().getHeight(); } @Override protected void onDraw(Canvas canvas) { // 画外圆 Paint paintCircle = new Paint(); paintCircle.setStyle(Paint.Style.STROKE); paintCircle.setAntiAlias(true); paintCircle.setStrokeWidth(5); canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, paintCircle); // 画刻度 Paint paintDegree = new Paint(); paintDegree.setStrokeWidth(3); for (int i = 0; i < 24; i++) { // 区分整点和非整点 if(i == 0 || i== 6 || i == 12 || i == 18){ paintDegree.setStrokeWidth(5); paintDegree.setTextSize(18); // 画长刻度 canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2, mWidth / 2, mHeight / 2 - mWidth / 2 + 30, paintDegree); // 画数字 String degree = String.valueOf(i); canvas.drawText(degree, mWidth / 2 - paintDegree.measureText(degree) / 2, mHeight / 2 - mWidth / 2 + 45, paintDegree); }else{ // 画短刻度 paintDegree.setStrokeWidth(3); paintDegree.setTextSize(15); canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2, mWidth / 2, mHeight / 2 - mWidth / 2 + 15, paintDegree); // 画数字 String degree = String.valueOf(i); canvas.drawText(degree, mWidth / 2 - paintDegree.measureText(degree) / 2, mHeight / 2 - mWidth / 2 + 30, paintDegree); } // 通过旋转画布简化坐标运算 canvas.rotate(15, mWidth / 2, mHeight / 2); } // 画中间指针,时针和分针 Paint paintHour = new Paint(); paintHour.setStrokeWidth(10); Paint paintMinute = new Paint(); paintMinute.setStrokeWidth(5); canvas.save(); // 开始位置移动到屏幕中心点 canvas.translate(mWidth / 2, mHeight / 2); canvas.drawLine(0, 0, 50, 50, paintHour); canvas.drawLine(0, 0, 50, 100, paintMinute); canvas.restore(); } }
1.2、Layer图层
Android中使用saveLayer()方法创建一个图层,图层是基于栈的结构进行管理的。
通过调用saveLayer()、saveLayerAlpha()方法将一个图层入栈,使用restore()、restoreToCount()方法将一个图层出栈。
入栈的时候,后面所有操作都发生在该图层上,出栈的时候,则会把图像绘制到上层的Canvas上。
@Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); mPaint.setColor(Color.BLUE); canvas.drawCircle(150, 150, 100, mPaint); canvas.saveLayerAlpha(0, 0, 400, 400, 127, LAYER_TYPE_NONE); mPaint.setColor(Color.RED); canvas.drawCircle(200, 200, 100, mPaint); canvas.restore(); }
图层透明度设置为0 - 255之间:
当透明度为127时,即半透明、当透明度为255时,即完全不透明、当透明度为0时,即完全透明。
三、色彩特效处理
1.1、色彩矩阵分析
在色彩处理中,通常使用以下三个角度来描述一个图像:
- 色调 ---- 物体传播的颜色
- 饱和度 ---- 颜色的纯度,从0(灰)到100%(饱和)来进行描述。
- 亮度 ---- 颜色的相对明暗程度。
在Android中,系统使用一个颜色矩阵--ColorMatrix,来处理图像的这些色彩效果。它是一个4 * 5 的数字矩阵,
它用来对图片的色彩进行处理。
对于图像中的任何一个像素点(由R、G、B、A组成),对该点应用颜色矩阵变换后,得到新的像素值。
其中我们不难发现其实颜色矩阵代表的就是红绿蓝和透明值,其中e、j、o、t称为偏移量。
- a、b、c、d、e --- 红色值
- f、g、h、i、j --- 绿色值
- k、l、m、n、o --- 蓝色值
- p、q、r、s、t --- 透明值
矩阵运算的乘法计算公式在线性代数中都学过,计算过程如下:
R1 = a x R + b x G + c x B + d x A + e; G1 = f x R + g x G + h x B + i x A + j; B1 = k x R + l x G + m x B + n x A + o; A1 = p x R + q x G + r x B + s x A + i;
待续。。。。。。。