1.代码示例
1.1 效果
原图 : 其尺寸为162 x 251,示例中的红点是变形的锚点.
变形之后:
1.2 代码
1 package com.e.weixin.session.view; 2 import com.e.weixin.R; 3 4 5 import android.content.Context; 6 import android.graphics.Bitmap; 7 import android.graphics.BitmapFactory; 8 import android.graphics.Canvas; 9 import android.graphics.Color; 10 import android.graphics.DashPathEffect; 11 import android.graphics.Matrix; 12 import android.graphics.Paint; 13 import android.graphics.Path; 14 import android.graphics.PathEffect; 15 import android.util.Log; 16 import android.view.View; 17 18 public class MatrixView extends View { 19 private Paint paint; 20 private Bitmap bitmap; 21 private Matrix matrix; 22 private final int bitmapWidth, bitmapHeight; 23 private int padding = 40; 24 25 // 打印Matrix内数据 26 void showMatrix(){ 27 // 下面的代码是为了查看matrix中的元素 28 float[] matrixValues = new float[9]; 29 matrix.getValues(matrixValues); 30 for (int i = 0; i < 3; ++i) { 31 String temp = new String(); 32 for (int j = 0; j < 3; ++j) { 33 temp += matrixValues[3 * i + j] + "\t"; 34 } 35 Log.e("Matrix", temp); 36 } 37 } 38 39 void drawFrameAndPivot(Canvas canvas, String txt, float column, float row, int pivotX, int pivotY){ 40 41 matrix.reset(); 42 43 float x = padding + (bitmapWidth + padding) * column ; 44 float y = padding + (bitmapHeight + padding) * row; 45 46 Path frame = new Path(); 47 48 // 画变形前的轮廓 49 frame.moveTo(x, y); 50 frame.lineTo(x + bitmapWidth, y); 51 frame.lineTo(x + bitmapWidth, y + bitmapHeight); 52 frame.lineTo(x, y + bitmapHeight); 53 frame.lineTo(x, y); 54 55 matrix.postTranslate(x, y); 56 57 paint.setColor(Color.BLACK); 58 paint.setStyle(Paint.Style.STROKE); 59 60 canvas.drawText(txt, x, y + bitmapHeight + paint.getTextSize(), paint); 61 62 canvas.drawPath(frame, paint); 63 // 画中心点(经过上面移动后), 64 paint.setColor(Color.RED); 65 paint.setStyle(Paint.Style.FILL); 66 canvas.drawCircle(x + pivotX, y + pivotY, 5, paint); 67 68 } 69 70 71 // 1. 平移 72 void translateMatrix(Canvas canvas){ 73 // 重置matrix 74 matrix.reset(); 75 76 // 开始平移 77 matrix.postTranslate(padding + (bitmapWidth + padding) * 1.5f, padding + (bitmapHeight + padding) * 0); 78 79 // 打印Matrix内数据 80 showMatrix(); 81 82 // 画出变换后的图像 83 canvas.drawBitmap(bitmap, matrix, paint); 84 85 // 画出变形前的轮廓 86 drawFrameAndPivot(canvas, "平移", 1, 0, 0, 0); 87 88 } 89 // 2. 缩放 90 void scaleMatrix(Canvas canvas){ 91 matrix.reset(); 92 93 // 开始缩放,第1个参数是在x轴的缩放比例,第2个是y轴。默认以(0,0)点 94 matrix.setScale(2.5f, 1.0f); 95 96 // 打印缩放前Matrix内数据 97 showMatrix(); 98 99 // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠 100 matrix.postTranslate(padding + (bitmapWidth + padding) * 2.5f,padding + ( bitmapHeight + padding ) * 0); 101 102 // 打印缩放后Matrix内数据 103 showMatrix(); 104 105 // 画出变换后的图像 106 canvas.drawBitmap(bitmap, matrix, paint); 107 108 // 画出变形前的轮廓 109 drawFrameAndPivot(canvas, "缩放(默认中心点是0,0)", 2.5f, 0, 0, 0); 110 } 111 // 3. 旋转(默认点) 112 void rotateMatrix2(Canvas canvas){ 113 matrix.reset(); 114 115 // 开始旋转,有旋转和平两个效果时,要先旋转再平移。 116 // 不指定旋转点时默认是图形的左,上点 117 matrix.setRotate(45f, 0, 0); 118 119 // 移动位置 120 matrix.postTranslate(padding + (bitmapWidth + padding) * 1f, padding + (bitmapHeight + padding) * 1); 121 122 // 打印Matrix内数据 123 showMatrix(); 124 125 // 画出变换后的图像 126 canvas.drawBitmap(bitmap, matrix, paint); 127 128 // 画出变形前的轮廓 129 drawFrameAndPivot(canvas, "旋转(默认中心点是0,0)", 1f, 1, 0, 0); 130 } 131 132 // 4. 旋转(指定一个旋转角度和中心点) 133 void rotateMatrix1(Canvas canvas){ 134 matrix.reset(); 135 136 // 开始旋转,有旋转和平两个效果时,要先旋转再平移。 137 // 第1个参数是角度,第2,3个参数是旋转中心点的坐标,它们最好在bitmap的宽高之内取值。 138 // 中心点的理解: 139 // 好比啬墙上有一幅画,右手食指按住画不动,然后左手拖动画做变形,旋转,绽放等动作。 140 // 其中右手食指按一点就是中心点,它一般在画内,但是也可以在画外。 141 matrix.setRotate(45f, bitmapWidth / 2, bitmapHeight / 2); 142 143 // 移动位置 144 matrix.postTranslate(padding + (bitmapWidth + padding) * 3f, padding + (bitmapHeight + padding) * 1); 145 146 // 打印Matrix内数据 147 showMatrix(); 148 149 // 画出变换后的图像 150 paint.setColor(Color.BLACK); 151 canvas.drawBitmap(bitmap, matrix, paint); 152 153 // 画出变形前的轮廓 154 drawFrameAndPivot(canvas, "旋转(指定中心点)", 3, 1, bitmapWidth / 2, bitmapHeight / 2); 155 156 } 157 // 5. 错切 - 水平 158 void hSkewMatrix(Canvas canvas){ 159 matrix.reset(); 160 161 // 打印Matrix变形前的数据 162 showMatrix(); 163 164 matrix.setSkew(0.5f, 0f); 165 166 // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠 167 matrix.postTranslate(padding + (bitmapWidth + padding) * 0f, padding + (bitmapHeight + padding) * 2); 168 169 // 打印Matrix变形后的数据 170 showMatrix(); 171 172 // 画出变换后的图像 173 canvas.drawBitmap(bitmap, matrix, paint); 174 175 // 画出变形前的轮廓 176 drawFrameAndPivot(canvas, "错切 - 水平", 0, 2, 0, 0); 177 } 178 // 6. 错切 - 垂直 179 void vSkewMatrix(Canvas canvas){ 180 matrix.reset(); 181 182 // 开始垂直错切, 183 matrix.setSkew(0f, 0.5f); 184 185 // 打印Matrix内数据 186 showMatrix(); 187 188 // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠 189 matrix.postTranslate(padding + (bitmapWidth + padding) * 1.6f, padding + (bitmapHeight + padding) * 2); 190 191 // 打印Matrix内数据 192 showMatrix(); 193 194 // 画出变换后的图像 195 canvas.drawBitmap(bitmap, matrix, paint); 196 197 // 画出变形前的轮廓 198 drawFrameAndPivot(canvas, "错切 - 垂直", 1.6f, 2, 0, 0); 199 } 200 // 7. 错切 - 水平 + 垂直 201 void hvSkewMatrix(Canvas canvas){ 202 matrix.reset(); 203 204 // 开始 水平 + 垂直 错切 205 matrix.setSkew(0.5f, 0.5f); 206 207 // 打印Matrix内数据 208 showMatrix(); 209 210 // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠 211 matrix.postTranslate(padding + (bitmapWidth + padding) * 3f, padding + (bitmapHeight + padding) * 2); 212 213 // 打印Matrix内数据 214 showMatrix(); 215 216 // 画出变换后的图像 217 canvas.drawBitmap(bitmap, matrix, paint); 218 219 // 画出变形前的轮廓 220 drawFrameAndPivot(canvas, "错切 - 水平 + 垂直", 3f, 2, 0, 0); 221 } 222 223 // 8. 对称 - 垂直 224 void vDcMatrix(Canvas canvas){ 225 matrix.reset(); 226 227 // 准备对称 228 float matrix_values[] = {-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f}; 229 matrix.setValues(matrix_values); 230 231 // 打印Matrix内数据 232 showMatrix(); 233 234 // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠 235 matrix.postTranslate(padding + (bitmapWidth + padding) * 0.7f, padding + (bitmapHeight + padding) * 4); 236 237 // 打印Matrix内数据 238 showMatrix(); 239 240 // 画出变换后的图像 241 canvas.drawBitmap(bitmap, matrix, paint); 242 243 // 画出变形前的轮廓 244 drawFrameAndPivot(canvas, "垂直对称", 0.7f, 4, 0, 0); 245 } 246 247 // 9. 对称 (水平对称) 248 void hDCMatrix(Canvas canvas){ 249 matrix.reset(); 250 251 // 准备对称 252 float matrix_values[] = {1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f}; 253 matrix.setValues(matrix_values); 254 255 // 打印Matrix内数据 256 showMatrix(); 257 258 // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠 259 matrix.postTranslate(padding + (bitmapWidth + padding) * 1.6f, padding + (bitmapHeight + padding) * 4f); 260 261 // 打印Matrix内数据 262 showMatrix(); 263 264 // 画出变换后的图像 265 canvas.drawBitmap(bitmap, matrix, paint); 266 267 // 画出变形前的轮廓 268 drawFrameAndPivot(canvas, "水平对称", 1.6f, 4f, 0, 0); 269 } 270 271 // 10. 对称(对称轴为直线y = x) 272 void dczMatrix(Canvas canvas){ 273 matrix.reset(); 274 275 // 准备对称 276 float matrix_values[] = {0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f}; 277 matrix.setValues(matrix_values); 278 279 // 打印Matrix内数据 280 showMatrix(); 281 282 // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠 283 matrix.postTranslate(padding + (bitmapWidth + padding) * 3.6f, padding + (bitmapHeight + padding) * 4f); 284 285 // 打印Matrix内数据 286 showMatrix(); 287 288 // 画出变换后的图像 289 canvas.drawBitmap(bitmap, matrix, paint); 290 291 // 画出变形前的轮廓 292 drawFrameAndPivot(canvas, "对称轴为直线y = x", 3.6f, 4f, 0, 0); 293 } 294 295 296 //============== 297 @Override 298 protected void onDraw(Canvas canvas) { 299 300 super.onDraw(canvas); 301 302 // 画出原图像 303 canvas.drawBitmap(bitmap, matrix, paint); 304 drawFrameAndPivot(canvas, "原图", 0, 0, 0, 0); 305 306 // 1. 平移 307 translateMatrix(canvas); 308 309 // 2. 缩放 310 scaleMatrix(canvas); 311 312 // 3. 旋转(默认中心点) 313 rotateMatrix2(canvas); 314 315 // 4. 旋转(指定一个旋转角度和中心点) 316 rotateMatrix1(canvas); 317 318 // 5. 错切 - 水平 319 hSkewMatrix(canvas); 320 321 // 6. 错切 - 垂直 322 vSkewMatrix(canvas); 323 324 // 7. 错切 - 水平 + 垂直 325 hvSkewMatrix(canvas); 326 327 // 8. 对称 - 垂直 328 vDcMatrix(canvas); 329 330 // 9. 对称 (水平对称) 331 hDCMatrix(canvas); 332 333 // 10. 对称(对称轴为直线y = x) 334 dczMatrix(canvas); 335 } 336 337 338 public MatrixView(Context context) { 339 super(context); 340 341 paint = new Paint(Paint.ANTI_ALIAS_FLAG); 342 PathEffect effects = new DashPathEffect(new float[]{5,5,5,5,5, 5}, 1); 343 paint.setStyle(Paint.Style.STROKE); 344 paint.setPathEffect(effects); 345 346 matrix = new Matrix(); 347 matrix.postTranslate(padding,padding);//默认位置 348 bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sophie); 349 bitmapWidth = bitmap.getWidth(); 350 bitmapHeight = bitmap.getHeight(); 351 352 } 353 354 @Override 355 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 356 // super.onMeasure(widthMeasureSpec, heightMeasureSpec); 357 // Try for a bitmapWidth based on our minimum 358 int w = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();//最小宽度 359 360 if(w == 0) w = 480; 361 //计算最佳值,在其中解析了widthMeasureSpec,这时如果w大于widthMeasureSpec中的值,则选widthMeasureSpec 362 w = resolveSizeAndState(w, widthMeasureSpec, 0); 363 364 365 // Whatever the w ends up being, ask for a bitmapHeight that would let the pie 366 // get as big as it can 367 int h = getSuggestedMinimumHeight() + getPaddingBottom() + getPaddingTop();//最小高度 368 369 if(h == 0) h = 800;//如果给出的建议是0,可以手动设置一个期望值。单位是像素。 370 371 h = resolveSizeAndState(h, heightMeasureSpec, 0);//计算最佳值,在其中解析了heightMeasureSpec 372 373 374 //将量算的结果保存到View的成员变量mMeasuredWidth 和mMeasuredHeight中。 375 setMeasuredDimension(w, h); 376 377 // 量算完成之后,View的父控件就可以通过调用 378 // getMeasuredWidth、getMeasuredState、getMeasuredWidthAndState 379 // 这三个方法获取View的量算结果。 380 } 381 382 }
2. 关于pre,set,post变形方式的区别
pre是在队列最前面插入,post是在队列最后面追加,而set先清空队列在添加。
2.1 示例1
1 matrix.preScale(2f,1f); 2 matrix.preTranslate(5f, 0f); 3 matrix.postScale(0.2f, 1f); 4 matrix.postTranslate(0.5f, 0f);
执行顺序:translate(5, 0) -> scale(2f, 1f) -> scale(0.2f, 1f) -> translate(0.5f, 0f)
2.2 示例2
1 matrix.postTranslate(2f, 0f); 2 matrix.preScale(0.2f, 1f); 3 matrix.setScale(1f, 1f); 4 matrix.postScale(5f, 1f); 5 matrix.preTranslate(0.5f, 0f);
执行顺序:translate(0.5f, 0f) -> scale(1f, 1f) -> scale(5f, 1) 执行了setScale后,前面两句设置的矩阵变化就不起作用了。(matrix.postTranslate(2f, 0f); matrix.preScale(0.2f, 1f); 不起作用)
注意其中的set系列,清除前面的变形.
3.变形时改变默认锚点
变形的默认锚点是左上(0,0),通常缩放或旋转等等变形操作希望改变默认的锚点,而调用view.setPivotX((float) viewWidth / 2); setPivotY或者在xml中 android:transformPivotX="200dp"不起作用,这时可用相应的系列变形方法如,
- postScale(float sx, float sy, float px, float py)
- postRotate(float degrees, float px, float py)
- setScale(float sx, float sy, float px, float py)
- setSkew(float kx, float ky, float px, float py)
- 等等...后面带有float px,float py的方法.
上面系列方法中的float px,float py 就是变形锚点.
4.变形的数学原理
矩阵中的MSCALE用于处理缩放变换,MSKEW用于处理错切变换,MTRANS用于处理平移变换,MPERSP用于处理透视变换。
http://www.cnblogs.com/qiengo/archive/2012/06/30/2570874.html