class BasicView2Draw extends View{ Paint paint; Bitmap bitmap; public BasicView2Draw(Context context) { super(context); paint = new Paint(Paint.ANTI_ALIAS_FLAG); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon); } private Bitmap createBitmap1(){ Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); Canvas canvas = new Canvas(bitmap1); canvas.drawColor(Color.BLUE); // canvas.drawARGB(0, 0, 0, 0);// 透明色 canvas.drawBitmap(bitmap, 0, 0, paint); canvas.drawText("Hello Android", 25, 55, paint); return bitmap1; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制位图 // 1.绘制位图在(10,10)位置上 canvas.drawBitmap(createBitmap1(), 10, 10, paint); // 2. canvas.drawBitmap(Bitmap bitmap,Rect src,Rect dest,Paint paint); // canvas.drawBitmap(Bitmap bitmap,Rect src,RectF dest,Paint paint); // 绘制位图到一个指定的矩形dest中,位图会自动进行平移和缩放等操作,如果src的参数不为null // 则会裁剪位图的部分区域来进行绘制 Rect rect = new Rect(10, 10, 50, 60); RectF rectF1 = new RectF(180.0f, 20.0f, 240.0f, 80.0f); RectF rectF2 = new RectF(180.0f, 100.0f, 240.0f, 160.0f); canvas.drawBitmap(createBitmap1(), null, rectF1, paint); canvas.drawBitmap(createBitmap1(), rect, rectF2, paint); // 点 paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setStrokeWidth(5.0f); paint.setColor(Color.YELLOW); canvas.drawPoints(new float[]{120,120,140,140,160,160,180,180}, paint); // 线 paint.reset();// 重置画笔 paint.setColor(Color.GREEN); paint.setAntiAlias(true); canvas.drawLine(30, 30, 130, 40, paint); paint.setColor(Color.RED); canvas.drawLines(new float[]{ 40,40,140,40 ,50,50,90,90 }, paint); // 矩形 paint.setColor(Color.CYAN); canvas.drawRect(10, 150, 150, 250, paint); paint.setColor(Color.GRAY); canvas.drawRect(new Rect(10, 260, 150, 280), paint); paint.setColor(Color.DKGRAY); canvas.drawRect(new RectF(20.2f, 290.9f, 120.2f, 300.3f), paint); // 绘制文本 // paint.setTextSize(20); // paint.setColor(0x40ffffff);// 半透明白色 // paint.setTextAlign(Paint.Align.RIGHT);// 对齐方向 // canvas.drawText("Cool Android", 250, 180, paint);// 这里注意,坐标(180,180)是文本的左下点坐标 // 画布平移: // 平移的单位是像素,分别是在x,y轴上平移的像素点 // 正数代表的正方向,x轴为平面的右侧,y轴为平面的下方,相应的,负数则向反方向平移 // canvas.translate(30.0f, 30.0f); // 画布缩放: // 参数分别是在想x,y轴上放大或缩小的倍数,大雨1为放大,小于1为缩小, // 缩放的原点默认为画布的原点(0,0),也可以指定缩放的原点 // canvas.scale(2.0f, 1.5f); // canvas.scale(0.5f, 0.5f, 100.0f, 100.0f);// 指定坐标(100.0f,100.0f)为缩放原点 // 这里剖析一下第二个缩放方法,其实系统为我们做的事情是这样的 /* scale(float sx, float sy, float px, float py){ translate(px,py); scale(sx,sy); translate(-px,-py); } */ // 画布旋转 // 1.以画布为原点,顺时针旋转40.0f度 // canvas.rotate(40.0f); // 2.以(100.11f, 100.22f)为原点,顺时针旋转50.0f度 // canvas.rotate(50.0f, 100.11f, 100.22f); // 相应的,为了加深理解,我们再剖析一下第二个旋转方法 // ,其实系统为我们做的事情是这样的 /* rotate(float degrees, float px, float py){ translate(px,py); rotate(degrees); translate(-px,-py); } */ // 画布倾斜 // skew(float sx,float xy);将画布在x及y轴方向上倾斜相应的角度,sx或sy为倾斜角度的tan值, // 如canvas.skew(1,0);为在x方向上倾斜45度 >> tan(45) = 1 // canvas.skew(1,0); } }
public class Matrix2Draw extends View {private Bitmap mBitmap;private Matrix mMatrix = new Matrix();public Matrix2Draw(Context context) {super(context);initialize();}private void initialize() {Bitmap bmp = ((BitmapDrawable)getResources().getDrawable(R.drawable.rotate_surfaceview)).getBitmap();mBitmap = bmp;/*首先,将缩放为100*100。这里scale的参数是比例。有一点要注意,如果直接用100/ bmp.getWidth()的话,会得到0,因为是整型相除,所以必须其中有一个是float型的, 直接用100f就好。*/mMatrix.setScale(100f/bmp.getWidth(), 100f/bmp.getHeight());/*// post 方式:后乘 >> 当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来完成所需的整个变换。 //平移到(100,100)处mMatrix.postTranslate(100, 100); //倾斜x和y轴,以(100,100)为中心。mMatrix.postSkew(0.2f, 0.2f, 100, 100);*/// pre 方式:前乘 >> 参数给出的矩阵乘以当前的矩阵。所以操作是在当前矩阵的最前面发生的。 //平移到(100,100)处mMatrix.preTranslate(100, 100); //倾斜x和y轴,以(100,100)为中心。mMatrix.preSkew(0.2f, 0.2f, 100, 100);}@Override protected void onDraw(Canvas canvas) {// super.onDraw(canvas); //如果界面上还有其他元素需要绘制,只需要将这句话写上就行了。Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);canvas.drawBitmap(mBitmap, mMatrix, paint);}}/** Matrix的操作: 总共分为translate(平移),rotate(旋转),scale(缩放)和skew(倾斜)四种,每一种变换在Android的API里都提供了set, post和pre三种操作方式,除了translate,其他三种操作都可以指定中心点。 set是直接设置Matrix的值,每次set一次,整个Matrix的数组都会变掉。 post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来完成所需的整个变换。 pre是前乘,参数给出的矩阵乘以当前的矩阵。所以操作是在当前矩阵的最前面发生的。 旋转、缩放和倾斜都可以围绕一个中心点来进行,如果不指定,默认情况下,是围绕(0,0)点来进行。 */
class BasicView2Draw extends View{ Paint paint; Bitmap bitmap; public BasicView2Draw(Context context) { super(context); paint = new Paint(Paint.ANTI_ALIAS_FLAG); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon); } private Bitmap createBitmap1(){ Bitmap bitmap1 = Bitmap.createBitmap(100, 100, Config.ARGB_8888); Canvas canvas = new Canvas(bitmap1); canvas.drawColor(Color.BLUE); // canvas.drawARGB(0, 0, 0, 0);// 透明色 canvas.drawBitmap(bitmap, 0, 0, paint); canvas.drawText("Hello Android", 25, 55, paint); return bitmap1; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制位图 // 1.绘制位图在(10,10)位置上 canvas.drawBitmap(createBitmap1(), 10, 10, paint); // 2. canvas.drawBitmap(Bitmap bitmap,Rect src,Rect dest,Paint paint); // canvas.drawBitmap(Bitmap bitmap,Rect src,RectF dest,Paint paint); // 绘制位图到一个指定的矩形dest中,位图会自动进行平移和缩放等操作,如果src的参数不为null // 则会裁剪位图的部分区域来进行绘制 Rect rect = new Rect(10, 10, 50, 60); RectF rectF1 = new RectF(180.0f, 20.0f, 240.0f, 80.0f); RectF rectF2 = new RectF(180.0f, 100.0f, 240.0f, 160.0f); canvas.drawBitmap(createBitmap1(), null, rectF1, paint); canvas.drawBitmap(createBitmap1(), rect, rectF2, paint); // 点 paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setStrokeWidth(5.0f); paint.setColor(Color.YELLOW); canvas.drawPoints(new float[]{120,120,140,140,160,160,180,180}, paint); // 线 paint.reset();// 重置画笔 paint.setColor(Color.GREEN); paint.setAntiAlias(true); canvas.drawLine(30, 30, 130, 40, paint); paint.setColor(Color.RED); canvas.drawLines(new float[]{ 40,40,140,40 ,50,50,90,90 }, paint); // 矩形 paint.setColor(Color.CYAN); canvas.drawRect(10, 150, 150, 250, paint); paint.setColor(Color.GRAY); canvas.drawRect(new Rect(10, 260, 150, 280), paint); paint.setColor(Color.DKGRAY); canvas.drawRect(new RectF(20.2f, 290.9f, 120.2f, 300.3f), paint); // 绘制文本 // paint.setTextSize(20); // paint.setColor(0x40ffffff);// 半透明白色 // paint.setTextAlign(Paint.Align.RIGHT);// 对齐方向 // canvas.drawText("Cool Android", 250, 180, paint);// 这里注意,坐标(180,180)是文本的左下点坐标 // 画布平移: // 平移的单位是像素,分别是在x,y轴上平移的像素点 // 正数代表的正方向,x轴为平面的右侧,y轴为平面的下方,相应的,负数则向反方向平移 // canvas.translate(30.0f, 30.0f); // 画布缩放: // 参数分别是在想x,y轴上放大或缩小的倍数,大雨1为放大,小于1为缩小, // 缩放的原点默认为画布的原点(0,0),也可以指定缩放的原点 // canvas.scale(2.0f, 1.5f); // canvas.scale(0.5f, 0.5f, 100.0f, 100.0f);// 指定坐标(100.0f,100.0f)为缩放原点 // 这里剖析一下第二个缩放方法,其实系统为我们做的事情是这样的 /* scale(float sx, float sy, float px, float py){ translate(px,py); scale(sx,sy); translate(-px,-py); } */ // 画布旋转 // 1.以画布为原点,顺时针旋转40.0f度 // canvas.rotate(40.0f); // 2.以(100.11f, 100.22f)为原点,顺时针旋转50.0f度 // canvas.rotate(50.0f, 100.11f, 100.22f); // 相应的,为了加深理解,我们再剖析一下第二个旋转方法 // ,其实系统为我们做的事情是这样的 /* rotate(float degrees, float px, float py){ translate(px,py); rotate(degrees); translate(-px,-py); } */ // 画布倾斜 // skew(float sx,float xy);将画布在x及y轴方向上倾斜相应的角度,sx或sy为倾斜角度的tan值, // 如canvas.skew(1,0);为在x方向上倾斜45度 >> tan(45) = 1 // canvas.skew(1,0); } }
package com.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Region; import android.util.AttributeSet; import android.view.View; /** * ---------------------------------------------------矩形区域------------------------------------------------- * canvas.clipRect(左上角x轴坐标, 左上角y轴坐标, 右下角x轴坐标, 右下角y轴坐标, Region.Op.XOR); * 最后一个参数有多个选择分别是: * //DIFFERENCE是第一次不同于第二次的部分显示出来 //REPLACE是显示第二次的 //REVERSE_DIFFERENCE 是第二次不同于第一次的部分显示 //INTERSECT:交集显示 //UNION:全部显示 //XOR补集,就是全集的减去交集剩余部分显示 * @author emmet1988.iteye.com * */ public class ClipRectDraw extends View { Context context; Paint paint; Path path; public ClipRectDraw(Context context) { super(context); init(); } public ClipRectDraw(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ClipRectDraw(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init(){ paint = new Paint(); paint.setAntiAlias(true); paint.setStrokeWidth(5); paint.setTextSize(15); paint.setTextAlign(Paint.Align.RIGHT); path = new Path(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GRAY); //左上图 canvas.save(); canvas.translate(10, 10); drawScene(canvas); canvas.restore(); //右上图 canvas.save(); canvas.translate(160, 10); canvas.clipRect(10, 10, 90, 90); canvas.clipRect(30, 30, 70, 70, Region.Op.XOR); drawScene(canvas); canvas.restore(); //左中图 canvas.save(); canvas.translate(10, 130); path.reset(); /*抛物曲线*/ path.cubicTo(0, 0, 100, 0, 100, 100); path.cubicTo(100, 100, 0, 100, 0, 0); canvas.clipPath(path, Region.Op.REPLACE); drawScene(canvas); canvas.restore(); //右中图 canvas.save(); canvas.translate(160, 130); canvas.clipRect(0, 0, 60, 60); canvas.clipRect(40, 40, 100, 100, Region.Op.UNION); drawScene(canvas); canvas.restore(); //左下图 canvas.save(); canvas.translate(10, 250); canvas.clipRect(0, 0, 60, 60); canvas.clipRect(40, 40, 100, 100, Region.Op.XOR); drawScene(canvas); canvas.restore(); //右下图 canvas.translate(160, 250); canvas.clipRect(0, 0, 60, 60); canvas.clipRect(40, 40, 100, 100, Region.Op.REVERSE_DIFFERENCE); drawScene(canvas); canvas.restore(); } private void drawScene(Canvas canvas){ canvas.clipRect(0, 0, 100, 100); canvas.drawColor(Color.WHITE); paint.setColor(Color.RED); canvas.drawLine(0, 0, 100, 100, paint); paint.setColor(Color.GREEN); canvas.drawCircle(30, 70, 30, paint); paint.setColor(Color.BLUE); canvas.drawText("ChenJianLi", 100, 30, paint); } }
package com.view; import com.test.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.view.View; /** * 在 Android 里面, Matrix 由 9 个 float 值构成,是一个 3*3 的矩阵。 * cosX, -sinX,translateX * sinX, cosX,translateY * 0, 0, scale * 解释一下,上面的 sinX 和 cosX ,表示旋转角度的 cos 值和 sin 值,注意, * 旋转角度是按顺时针方向计算的。 translateX 和 translateY 表示 x 和 y 的平移量。 * scale 是缩放的比例, 1 是不变, 2 是表示缩放 1/2 , * @author emmet1988.iteye.com * */ public class MatrixDraw extends View implements Runnable{ Bitmap bitmap; Matrix matrix = new Matrix(); Paint paint; public MatrixDraw(Context context) { super(context); bitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.rotate_surfaceview)).getBitmap(); paint = new Paint(); paint.setAntiAlias(true); new Thread(this).start(); } float m; float n; @Override protected void onDraw(Canvas canvas) { /* float cosValue = (float)Math.cos(-Math.PI/m); float sinValue = (float)Math.sin(-Math.PI/m); Log.d("matrixdraw", "Math.PI =" + Math.PI); Log.d("matrixdraw", "Math.PI/m =" + Math.PI/m); Log.d("matrixdraw", "Math.cos(-Math.PI/m) =" + (float)Math.cos(-Math.PI/m)); Log.d("matrixdraw", "Math.sin(-Math.PI/m) =" + (float)Math.sin(-Math.PI/m)); matrix.setValues(new float[]{ cosValue,-sinValue,100, sinValue,cosValue,100, 0, 0, 2 });//举例,若缩放值为0.9,代表放大原图的十分之一 // super.onDraw(canvas);//当然,如果界面上还有其他元素需要绘制,只需要将这句话写上就行了。 // Matrix matrix2 = new Matrix(matrix); canvas.drawBitmap(bitmap, matrix, paint); // canvas.drawBitmap(bitmap, matrix2, paint); */ n ++; if (n == 60) { n = 0; } matrix.postRotate(n); matrix.postTranslate(n, n); matrix.postScale(1, 1, n, n); canvas.drawBitmap(bitmap, matrix, paint); } @Override public void run() { while(!Thread.currentThread().isInterrupted()){ try { Thread.sleep(100); postInvalidate(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } /** * 以左上角为顶点,缩放一半,逆时针旋转30度, * 然后沿x轴和y轴分别平移50个像素, * 代码 里面写的是100,为什么是平移50呢, * 因为缩放了一半。 * 大家可以自己设置一下Matrix的值,或者尝试一下两个 * Matrix相乘,得到的值设置进去, * 这样才能对Matrix更加熟练。 */ }
package com.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.view.View; public class SimpleDraw extends View implements Runnable { /* * 我们继续来介绍Android平台底层绘图类的相关内容,在Android UI开发专题(一) * 之界面设计中我们介绍了有关Android平台资源使用以及Bitmap相关类的操作 * ,接下来将会以实例的方式给大家演示各种类的用处以及注意点。今天我们继续 * 了解android.graphics包中比较重要的绘图类。 * * 一、 android.graphics.Matrix有关图形的变换、缩放等相关操作常用的方法有: * Java代码: void reset() // 重置一个matrix对象。 * void set(Matrix src) //复制一个源矩阵,和本类的构造方法 Matrix(Matrix src) 一样 * boolean isIdentity() //返回这个矩阵是否定义(已经有意义) * void setRotate(float degrees) //指定一个角度以0,0为坐标进行旋转 * void setRotate(float degrees, float px, float py) //指定一个角度以px,py为坐标进行旋转 * void setScale(float sx, float sy) // 缩放 * void setScale(float sx, float sy, float px, float py) //以坐标px,py进行缩放 * void setTranslate(float dx, float dy) //平移 * void setSkew (float kx, float ky, float px, float py) //以坐标px,py进行倾斜 * void setSkew (float kx, float ky) //倾斜 复制代码 二、android.graphics.NinePatch * * NinePatch是Android平台特有的一种非矢量图形自然拉伸处理方法,可以帮助常规的 * 图形在拉伸时不会缩放, * 实例中Android开发网提示大家对于Toast的显示就是该原理,同时SDK中提供了一 * 个工具名为Draw * 9-Patch,有关该工具的使用方法可以参考我们经发布的 Draw * 9-Patch使用方法介绍一文。由于该类提供了高质量支持透明的缩放方式,所以图形 * 格式为PNG,文件命名方式为.9.png * 的后缀比如eoeandroid。 * * 三、android.graphics.Paint。Paint类我们可以理解为画笔、画刷的属性定义,本类 * 常用的方法如下: * * Java代码: void reset() //重置 * void setARGB(int a, int r, int g, int b) 或 void setColor(int color) * //均为设置Paint对象的颜色 * void setAntiAlias(boolean aa) * * //是否抗锯齿,需要配合void setFlags (Paint.ANTI_ALIAS_FLAG) 来帮助消除锯齿 * 使其边缘更平滑。 * Shader setShader(Shader shader) * * //设置阴影,Shader类是一个矩阵对象,如果为NULL将清除阴影。 * void setStyle(Paint.Style style) //设置样式,一般为 FILL 填充,或者STROKE凹陷 * 效果。 * void setTextSize(float textSize) //设置字体大小 * void setTextAlign(Paint.Align align) //文本对齐方式 * Typeface setTypeface(Typeface typeface) * //设置字体,通过Typeface可以加载Android内部的字体,一般为宋体对于中文, * 部分ROM可以自己添加比如雅黑等等 * void setUnderlineText(boolean underlineText) * * //是否设置下划线,需要撇和void setFlags (Paint.UNDERLINE_TEXT_FLAG) 方法。 复制代码 * 四、android.graphics.Rect * * Rect我们可以理解为矩形区域,类似的还有Point一个点,Rect类除了表示一个矩 * 形区域位置描述外, * eoeandroid提示主要可以帮助我们计算图形之间是否碰撞 * (包含)关系,对于Android游戏开发比较有用,其主要的成员contains包含了三种 * 重载方法,来判断包含关系. * * Java代码: * boolean contains(int left, int top, int right, int bottom) * boolean contains(int x, int y) * * boolean contains(Rect r) 复制代码 五、android.graphics.Region * Region在Android平台中表示一个区域和Rect不同的是 * ,它表示的是一个不规则的样子,可以是椭圆、多边形等等,而Rect仅仅是矩形。 * 同样Region的boolean contains(int x, * int y) 成员可以判断一个点是否在该区域内。 * * 六、android.graphics.Typeface * Typeface类是帮助描述一个字体对象,在TextView中通过使用setTypeface方法来 * 制定一个输出文本的字体 * ,其直接构造调用成员create方法可以直接指定一个字体名称和样式,比如 * Java代码: static Typeface create(Typeface family, int style) * * static Typeface create(String familyName, int style) 复制代码 * 同时使用isBold和isItalic方法可以判断出是否包含粗体或斜体的字型。 * * Java代码: final boolean isBold() * final boolean isItalic() 复制代码 该类的创建方法还有从apk的资源或从一个具体的 * 文件路径,其具体方法为 * Java代码: static Typeface createFromAsset(AssetManager mgr, String path) * static Typeface createFromFile(File path) * static Typeface createFromFile(String path) 复制代码 */ private Paint paint; public SimpleDraw(Context context) { super(context); paint = new Paint(); new Thread(this).start(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GRAY);// paint.setAntiAlias(true);// canvas.save();// canvas.clipRect(10, 10, 110, 110);// canvas.drawColor(Color.WHITE);// // canvas.rotate(m);//以屏幕左上角为坐标原点旋转 m += 45.0f; if (m == 360.0f) { m = 0.0f; } canvas.rotate(m, 60, 60);// 以(60,60)为原点旋转 paint.setColor(Color.GREEN); canvas.drawRect(new Rect(50, 50, 70, 70), paint); canvas.restore(); canvas.save(); canvas.translate(140, 10); canvas.clipRect(0, 0, 100, 100);// 一定要先剪辑出矩形区域再设画布背景, //否则会覆盖整张画布 canvas.drawColor(Color.BLACK); paint.setColor(Color.BLUE); canvas.drawRect(new Rect(10, 10, 50, 50), paint); canvas.restore(); // canvas.save(); canvas.translate(120, 120); canvas.clipRect(new Rect(0, 0, 100, 100)); canvas.drawColor(Color.GREEN); // paint.setColor(Color.BLUE); paint.setStrokeWidth(4); paint.setColor(Color.BLACK); canvas.drawLine(0, 60, 100, 60, paint); paint.setARGB(255, 51, 51, 51); paint.setTextSize(20); paint.setFlags(Paint.ANTI_ALIAS_FLAG); paint.setUnderlineText(true); // paint.setFlags(Paint.UNDERLINE_TEXT_FLAG); canvas.drawText("陈建立", 25, 80, paint); paint.setColor(Color.WHITE); canvas.drawRect(new Rect(10, 10, 50, 50), paint); canvas.restore(); } float m = 0.0f; public void run() { while (!Thread.currentThread().isInterrupted()) { try { Thread.sleep(500);// 每半秒执行一次 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } postInvalidate(); } } }package com.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.FontMetrics; import android.util.Log; import android.view.View; public class TextDraw extends View { public TextDraw(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint textPaint = new Paint( Paint.ANTI_ALIAS_FLAG); textPaint.setTextSize( 35); textPaint.setColor( Color.WHITE); // FontMetrics FontMetrics fontMetrics = textPaint.getFontMetrics(); String text = "abcdefghijklm"; // float baseX = 0; float baseY = 100; Log.d("textDraw", "top = "+fontMetrics.top+ "ascent = "+fontMetrics.ascent+ "descent = "+fontMetrics.descent+ "bottom = "+fontMetrics.bottom+"\n"); float topY = baseY + fontMetrics.top; float ascentY = baseY + fontMetrics.ascent; float descentY = baseY + fontMetrics.descent; float bottomY = baseY + fontMetrics.bottom; Log.d("textDraw", "topY = "+topY+ "ascentY = "+ascentY+ "descentY = "+descentY+ "bottomY = "+bottomY); // canvas.drawText( text, baseX, baseY, textPaint); // BaseLine Paint baseLinePaint = new Paint( Paint.ANTI_ALIAS_FLAG); baseLinePaint.setColor( Color.RED); canvas.drawLine(0, baseY, getWidth(), baseY, baseLinePaint); // Base canvas.drawCircle( baseX, baseY, 5, baseLinePaint); // TopLine Paint topLinePaint = new Paint( Paint.ANTI_ALIAS_FLAG); topLinePaint.setColor( Color.LTGRAY); canvas.drawLine(0, topY, getWidth(), topY, topLinePaint); // AscentLine Paint ascentLinePaint = new Paint( Paint.ANTI_ALIAS_FLAG); ascentLinePaint.setColor( Color.GREEN); canvas.drawLine(0, ascentY, getWidth(), ascentY, ascentLinePaint); // DescentLine Paint descentLinePaint = new Paint( Paint.ANTI_ALIAS_FLAG); descentLinePaint.setColor( Color.YELLOW); canvas.drawLine(0, descentY, getWidth(), descentY, descentLinePaint); // ButtomLine Paint bottomLinePaint = new Paint( Paint.ANTI_ALIAS_FLAG); bottomLinePaint.setColor( Color.MAGENTA); canvas.drawLine(0, bottomY, getWidth(), bottomY, bottomLinePaint); } }class RoundImageView extends View { private Bitmap bitmap; int bitmapWidth; int bitmapHeight; public RoundImageView(Context context) { super(context); bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.rotate_surfaceview); bitmapWidth = bitmap.getWidth(); bitmapHeight = bitmap.getHeight(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 第一种方法: /*Bitmap roundBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight,Bitmap.Config.ARGB_8888); canvas = new Canvas(roundBitmap); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLUE); canvas.drawRoundRect(new RectF(0, 0, bitmapWidth, bitmapHeight),20.0f, 20.0f, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); canvas.drawBitmap(bitmap, 0, 0, null); canvas.drawBitmap(roundBitmap, 0, 0, paint);*/ // 第二种方法: Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(0xffffffff); paint.setTextSize(15); canvas.drawText("生成带圆角的图片", 10, 25, paint); canvas.drawBitmap(getRoundedCornerBitmap(bitmap), 10, 30, paint); canvas.drawText("生成带倒影的图片", 170, 160, paint); canvas.drawBitmap(createReflectionImageWithOrigin(bitmap), 170, 165, paint); } public Bitmap getRoundedCornerBitmap(Bitmap bitmap) { // 创建一个指定宽度和高度的空位图对象 Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Config.ARGB_8888); // 用该位图创建画布 Canvas canvas = new Canvas(output); // 画笔对象 final Paint paint = new Paint(); // 画笔的颜色 final int color = 0xff424242; // 矩形区域对象 final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); // 未知 final RectF rectF = new RectF(rect); // 拐角的半径 final float roundPx = 12; // 消除锯齿 paint.setAntiAlias(true); // 画布背景色 canvas.drawARGB(0, 0, 0, 0); // 设置画笔颜色 paint.setColor(color); // 绘制圆角矩形 canvas.drawRoundRect(rectF, roundPx, roundPx,paint); // 未知 paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); // 把该图片绘制在该圆角矩形区域中 canvas.drawBitmap(bitmap, rect, rect, paint); // 最终在画布上呈现的就是该圆角矩形图片,然后我们返回该Bitmap对象 return output; } //获得带倒影的图片方法 public Bitmap createReflectionImageWithOrigin(Bitmap bitmap){ // 图片与倒影之间的距离间隔 final int reflectionGap = 2; // 原图的宽度 int width = bitmap.getWidth(); // 原图的高度 int height = bitmap.getHeight(); // 图片旋转,缩放等控制对象 Matrix matrix = new Matrix(); // 缩放(这里pre,set,post三种效果是不一样的,注意区别) matrix.preScale(1, -1); /** set是直接设置Matrix的值,每次set一次,整个Matrix的数组都会变掉。 post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post, 来完成所需的整个变换。例如,要将一个图片旋 转30度,然后平移到(100,100)的地方,那么可以这样做: Matrix m = new Matrix(); m.postRotate(30); m.postTranslate(100, 100); 这样就达到了想要的效果。 pre是前乘,参数给出的矩阵乘以当前的矩阵。所以操作是在当前矩阵的最前面发生的。 例如上面的例子,如果用pre的话,就要这样: Matrix m = new Matrix(); m.setTranslate(100, 100); m.preRotate(30); 旋转、缩放和倾斜都可以围绕一个中心点来进行,如果不指定,默认情况下, 是围绕(0,0)点来进行。 关于缩放: scale的参数是比例。例如,我们缩放为100%,则有一点要注意,如果直接用 100/bmp.getWidth()的话,会得到0,因为是整型相除,所以必须其中有一个是 float型的,直接用100f就好 。 如:matrix.setScale(100f/bmp.getWidth(), 100f/bmp.getHeight()); */ // 创建一个初始的倒影位图 Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, height/2, width, height/2, matrix, false); // 新建一个宽度为原图宽度,高度为原图高度的3/2的位图,用于绘制新的位图,即整体的效果图位图对象 Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height/2), Config.ARGB_8888); // 由该位图对象创建初始画布(规定了画布的宽高) Canvas canvas = new Canvas(bitmapWithReflection); // 在该画布上绘制原图 canvas.drawBitmap(bitmap, 0, 0, null); // 创建一个画笔 Paint deafalutPaint = new Paint(); // 绘制一个矩形区域,该矩形区域便是原图和倒影图之间的间隔图 canvas.drawRect(0, height,width,height + reflectionGap,deafalutPaint); // 绘制该倒影图于间隔图的下方 canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null); // 创建一个画笔 Paint paint = new Paint(); // 创建一个线性渐变对象 LinearGradient shader = new LinearGradient( 0, bitmap.getHeight(), 0, bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff, TileMode.CLAMP ); // 把渐变效果应用在画笔上 paint.setShader(shader); // Set the Transfer mode to be porter duff and destination in // 未知 paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); // Draw a rectangle using the paint with our linear gradient // 绘制出该渐变效果,也就是最终的倒影效果图 canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint); // 返回 return bitmapWithReflection; } } /** * 绘制圆角背景以及图片圆角的处理 .配置文件实现 <?xml version="1.0" encoding="utf-8"?> <layer-list * xmlns:android="http://schemas.android.com/apk/res/android"> <item * android:drawable="@drawable/icon_home_button_img"/> <item * android:drawable="@drawable/icon_home_shape_overlay"/> * </layer-list> * icon_home_shape_overlay如下 * <?xml version="1.0" encoding="utf-8"?> * <shape * xmlns:android="http://schemas.android.com/apk/res/android"> <solid * android:color="#60000000"/> * <stroke android:width="3dp" * color="#ff000000"/> * <corners android:radius="10dp" /> * </shape> * 或者直接使用一种效果 * <?xml version="1.0" encoding="UTF-8"?> * <shape * xmlns:android="http://schemas.android.com/apk/res/android"> * <solid * android:color="#99FFFFFF"/> * <corners android:radius="30px"/> * <padding * android:left="0dp" android:top="0dp" android:right="0dp" * android:bottom="0dp" /> * </shape> * 然后 * android:background="@drawable/my_shape_file" * * * 2.图片本身加上圆角 Bitmap myCoolBitmap = ... ; // <-- Your bitmap you want rounded * * int w = myCoolBitmap.getWidth(), h = myCoolBitmap.getHeight(); * Bitmap rounder = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888); Canvas * canvas = new Canvas(rounder); * * Paint xferPaint = new Paint(Paint.ANTI_ALIAS_FLAG); * xferPaint.setColor(Color.RED); * * canvas.drawRoundRect(new RectF(0,0,w,h), 20.0f, 20.0f, xferPaint); * * xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); * canvas.drawBitmap(myCoolBitmap, 0,0, null); * canvas.drawBitmap(rounder, 0,0, xferPaint); * 或者 * public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) { * Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), * bitmap.getHeight(), Config.ARGB_8888); * Canvas canvas = newCanvas(output); * * final int color = 0xff424242; final Paint paint = new Paint(); final Rect * rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF * rectF = new RectF(rect); final float roundPx = 12; * * paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); * paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx,paint); * * paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); * canvas.drawBitmap(bitmap, rect, rect, paint); * * return output; * } */package com.view; import com.test.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * http://wallage.blog.163.com/blog/static/173896242010101232220959/ * @author emmet1988.iteye.com * */ public class SurfaceViewDraw extends SurfaceView implements Runnable,SurfaceHolder.Callback { private Bitmap backgroundBitmap; private Bitmap rotateBitmap; SurfaceHolder surfaceHolder; public SurfaceViewDraw(Context context) { super(context); backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.background_surfaceview); rotateBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rotate_surfaceview); surfaceHolder = this.getHolder(); surfaceHolder.addCallback(this); } public void surfaceCreated(SurfaceHolder holder) { new Thread(this).start(); Log.d("surfaceview", "surfaceCreated"); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.d("surfaceview", "surfaceChanged"); } public void surfaceDestroyed(SurfaceHolder holder) { Log.d("surfaceview", "surfaceDestroyed"); } @Override public void run() { Log.d("surfaceview", "run"); Canvas canvas = null; int rotateValue = 0;//旋转角度 int frameCount = 0;//帧计数器 while (!Thread.currentThread().isInterrupted()) { try { // canvas = surfaceHolder.lockCanvas();//获取画布对象(获取整个屏幕的画布) canvas = surfaceHolder.lockCanvas(new Rect(10, 10, 240, 250));//获取某个区域的画布 Paint paint = new Paint(); Log.d("surfaceview", "rotateValue " +rotateValue+"|frameCount "+frameCount); if (frameCount++ < 2) {//仅在第一次绘制时绘制背景 /* * 这里为什么设置成<2,而不是1,是由于SurfaceView本身的双缓冲技术。 覆盖刷新其实就是将每次的新的图形绘制到上一帧去, 所以如果图像是半透明的,就要考虑重复叠加导致的问题了, 而如果是完全不透明的图形则不会有任何问题。 背景会在背景图和黑色背景之间来回闪。 这个问题其实是源于SurfaceView的双缓冲机制,我理解就是它会缓冲 前两帧的图像交替传递给后面的帧用作覆盖,这样由于我们仅在第一帧 绘制了背景,第二帧就是无背景状态了,且通过双缓冲机制一直保持下 来,解决办法就是改为在前两帧都进行背景绘制。 */ canvas.drawBitmap(backgroundBitmap, 0, 0, paint);//绘制背景 } //创建矩阵以控制图片的旋转和平移 Matrix matrix = new Matrix(); rotateValue += 40; matrix.setRotate(rotateValue, rotateBitmap.getWidth()/2, rotateBitmap.getHeight()/2); // matrix.postRotate(rotateValue, rotateBitmap.getWidth()/2, rotateBitmap.getHeight()/2); // matrix.setTranslate(100, rotateValue); if (rotateValue == 360) { rotateValue = 0; } matrix.setTranslate(80,50);//设置左边距和上边距 //绘制问号 Log.d("surfaceview", "canvas "+canvas); Log.d("surfaceview", "rotateBitmap "+rotateBitmap); Log.d("surfaceview", "matrix "+matrix); Log.d("surfaceview", "paint "+paint); if (canvas != null) { canvas.drawBitmap(rotateBitmap, matrix, paint); //解锁画布,提交画好的图像 surfaceHolder.unlockCanvasAndPost(canvas); } Thread.sleep(30); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Log.d("surfaceview", "InterruptedException"); } finally { Log.d("surfaceview", "finally"); } } } }