1.代码示例

1.1 效果

  原图 : 其尺寸为162 x 251,示例中的红点是变形的锚点.

  

  变形之后:

  

  

1.2 代码

 package com.e.weixin.session.view;
import com.e.weixin.R; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.util.Log;
import android.view.View; public class MatrixView extends View {
private Paint paint;
private Bitmap bitmap;
private Matrix matrix;
private final int bitmapWidth, bitmapHeight;
private int padding = ; // 打印Matrix内数据
void showMatrix(){
// 下面的代码是为了查看matrix中的元素
float[] matrixValues = new float[];
matrix.getValues(matrixValues);
for (int i = ; i < ; ++i) {
String temp = new String();
for (int j = ; j < ; ++j) {
temp += matrixValues[ * i + j] + "\t";
}
Log.e("Matrix", temp);
}
} void drawFrameAndPivot(Canvas canvas, String txt, float column, float row, int pivotX, int pivotY){ matrix.reset(); float x = padding + (bitmapWidth + padding) * column ;
float y = padding + (bitmapHeight + padding) * row; Path frame = new Path(); // 画变形前的轮廓
frame.moveTo(x, y);
frame.lineTo(x + bitmapWidth, y);
frame.lineTo(x + bitmapWidth, y + bitmapHeight);
frame.lineTo(x, y + bitmapHeight);
frame.lineTo(x, y); matrix.postTranslate(x, y); paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE); canvas.drawText(txt, x, y + bitmapHeight + paint.getTextSize(), paint); canvas.drawPath(frame, paint);
// 画中心点(经过上面移动后),
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(x + pivotX, y + pivotY, , paint); } // 1. 平移
void translateMatrix(Canvas canvas){
// 重置matrix
matrix.reset(); // 开始平移
matrix.postTranslate(padding + (bitmapWidth + padding) * 1.5f, padding + (bitmapHeight + padding) * ); // 打印Matrix内数据
showMatrix(); // 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "平移", , , , ); }
// 2. 缩放
void scaleMatrix(Canvas canvas){
matrix.reset(); // 开始缩放,第1个参数是在x轴的缩放比例,第2个是y轴。默认以(0,0)点
matrix.setScale(2.5f, 1.0f); // 打印缩放前Matrix内数据
showMatrix(); // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
matrix.postTranslate(padding + (bitmapWidth + padding) * 2.5f,padding + ( bitmapHeight + padding ) * ); // 打印缩放后Matrix内数据
showMatrix(); // 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "缩放(默认中心点是0,0)", 2.5f, , , );
}
// 3. 旋转(默认点)
void rotateMatrix2(Canvas canvas){
matrix.reset(); // 开始旋转,有旋转和平两个效果时,要先旋转再平移。
// 不指定旋转点时默认是图形的左,上点
matrix.setRotate(45f, , ); // 移动位置
matrix.postTranslate(padding + (bitmapWidth + padding) * 1f, padding + (bitmapHeight + padding) * ); // 打印Matrix内数据
showMatrix(); // 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "旋转(默认中心点是0,0)", 1f, , , );
} // 4. 旋转(指定一个旋转角度和中心点)
void rotateMatrix1(Canvas canvas){
matrix.reset(); // 开始旋转,有旋转和平两个效果时,要先旋转再平移。
// 第1个参数是角度,第2,3个参数是旋转中心点的坐标,它们最好在bitmap的宽高之内取值。
// 中心点的理解:
// 好比啬墙上有一幅画,右手食指按住画不动,然后左手拖动画做变形,旋转,绽放等动作。
// 其中右手食指按一点就是中心点,它一般在画内,但是也可以在画外。
matrix.setRotate(45f, bitmapWidth / , bitmapHeight / ); // 移动位置
matrix.postTranslate(padding + (bitmapWidth + padding) * 3f, padding + (bitmapHeight + padding) * ); // 打印Matrix内数据
showMatrix(); // 画出变换后的图像
paint.setColor(Color.BLACK);
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "旋转(指定中心点)", , , bitmapWidth / , bitmapHeight / ); }
// 5. 错切 - 水平
void hSkewMatrix(Canvas canvas){
matrix.reset(); // 打印Matrix变形前的数据
showMatrix(); matrix.setSkew(0.5f, 0f); // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
matrix.postTranslate(padding + (bitmapWidth + padding) * 0f, padding + (bitmapHeight + padding) * ); // 打印Matrix变形后的数据
showMatrix(); // 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "错切 - 水平", , , , );
}
// 6. 错切 - 垂直
void vSkewMatrix(Canvas canvas){
matrix.reset(); // 开始垂直错切,
matrix.setSkew(0f, 0.5f); // 打印Matrix内数据
showMatrix(); // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
matrix.postTranslate(padding + (bitmapWidth + padding) * 1.6f, padding + (bitmapHeight + padding) * ); // 打印Matrix内数据
showMatrix(); // 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "错切 - 垂直", 1.6f, , , );
}
// 7. 错切 - 水平 + 垂直
void hvSkewMatrix(Canvas canvas){
matrix.reset(); // 开始 水平 + 垂直 错切
matrix.setSkew(0.5f, 0.5f); // 打印Matrix内数据
showMatrix(); // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
matrix.postTranslate(padding + (bitmapWidth + padding) * 3f, padding + (bitmapHeight + padding) * ); // 打印Matrix内数据
showMatrix(); // 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "错切 - 水平 + 垂直", 3f, , , );
} // 8. 对称 - 垂直
void vDcMatrix(Canvas canvas){
matrix.reset(); // 准备对称
float matrix_values[] = {-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f};
matrix.setValues(matrix_values); // 打印Matrix内数据
showMatrix(); // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
matrix.postTranslate(padding + (bitmapWidth + padding) * 0.7f, padding + (bitmapHeight + padding) * ); // 打印Matrix内数据
showMatrix(); // 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "垂直对称", 0.7f, , , );
} // 9. 对称 (水平对称)
void hDCMatrix(Canvas canvas){
matrix.reset(); // 准备对称
float matrix_values[] = {1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f};
matrix.setValues(matrix_values); // 打印Matrix内数据
showMatrix(); // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
matrix.postTranslate(padding + (bitmapWidth + padding) * 1.6f, padding + (bitmapHeight + padding) * 4f); // 打印Matrix内数据
showMatrix(); // 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "水平对称", 1.6f, 4f, , );
} // 10. 对称(对称轴为直线y = x)
void dczMatrix(Canvas canvas){
matrix.reset(); // 准备对称
float matrix_values[] = {0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f};
matrix.setValues(matrix_values); // 打印Matrix内数据
showMatrix(); // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
matrix.postTranslate(padding + (bitmapWidth + padding) * 3.6f, padding + (bitmapHeight + padding) * 4f); // 打印Matrix内数据
showMatrix(); // 画出变换后的图像
canvas.drawBitmap(bitmap, matrix, paint); // 画出变形前的轮廓
drawFrameAndPivot(canvas, "对称轴为直线y = x", 3.6f, 4f, , );
} //==============
@Override
protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 画出原图像
canvas.drawBitmap(bitmap, matrix, paint);
drawFrameAndPivot(canvas, "原图", , , , ); // 1. 平移
translateMatrix(canvas); // 2. 缩放
scaleMatrix(canvas); // 3. 旋转(默认中心点)
rotateMatrix2(canvas); // 4. 旋转(指定一个旋转角度和中心点)
rotateMatrix1(canvas); // 5. 错切 - 水平
hSkewMatrix(canvas); // 6. 错切 - 垂直
vSkewMatrix(canvas); // 7. 错切 - 水平 + 垂直
hvSkewMatrix(canvas); // 8. 对称 - 垂直
vDcMatrix(canvas); // 9. 对称 (水平对称)
hDCMatrix(canvas); // 10. 对称(对称轴为直线y = x)
dczMatrix(canvas);
} public MatrixView(Context context) {
super(context); paint = new Paint(Paint.ANTI_ALIAS_FLAG);
PathEffect effects = new DashPathEffect(new float[]{,,,,, }, );
paint.setStyle(Paint.Style.STROKE);
paint.setPathEffect(effects); matrix = new Matrix();
matrix.postTranslate(padding,padding);//默认位置
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sophie);
bitmapWidth = bitmap.getWidth();
bitmapHeight = bitmap.getHeight(); } @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Try for a bitmapWidth based on our minimum
int w = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();//最小宽度 if(w == ) w = ;
//计算最佳值,在其中解析了widthMeasureSpec,这时如果w大于widthMeasureSpec中的值,则选widthMeasureSpec
w = resolveSizeAndState(w, widthMeasureSpec, ); // Whatever the w ends up being, ask for a bitmapHeight that would let the pie
// get as big as it can
int h = getSuggestedMinimumHeight() + getPaddingBottom() + getPaddingTop();//最小高度 if(h == ) h = ;//如果给出的建议是0,可以手动设置一个期望值。单位是像素。 h = resolveSizeAndState(h, heightMeasureSpec, );//计算最佳值,在其中解析了heightMeasureSpec //将量算的结果保存到View的成员变量mMeasuredWidth 和mMeasuredHeight中。
setMeasuredDimension(w, h); // 量算完成之后,View的父控件就可以通过调用
// getMeasuredWidth、getMeasuredState、getMeasuredWidthAndState
// 这三个方法获取View的量算结果。
} }

2. 关于pre,set,post变形方式的区别

  pre是在队列最前面插入,post是在队列最后面追加,而set先清空队列在添加。

2.1 示例1

     matrix.preScale(2f,1f);
matrix.preTranslate(5f, 0f);
matrix.postScale(0.2f, 1f);
matrix.postTranslate(0.5f, 0f);

  执行顺序:translate(5, 0) -> scale(2f, 1f) -> scale(0.2f, 1f) -> translate(0.5f, 0f)

2.2 示例2

     matrix.postTranslate(2f, 0f);
matrix.preScale(0.2f, 1f);
matrix.setScale(1f, 1f);
matrix.postScale(5f, 1f);
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

自定义View(11)**在onDraw中使用矩阵Matrix的更多相关文章

  1. Android 自定义View及其在布局文件中的使用示例

    前言: 尽管Android已经为我们提供了一套丰富的控件,如:Button,ImageView,TextView,EditText等众多控件,但是,有时候在项目开发过程中,还是需要开发者自定义一些需要 ...

  2. Android自定义View研究--View中的原点坐标和XML中布局自定义View时View触摸原点问题

    这里只做个汇总~.~独一无二 文章出处:http://blog.csdn.net/djy1992/article/details/9715047 Android自定义View研究--View中的原点坐 ...

  3. Android中实现自定义View组件并使其能跟随鼠标移动

    场景 实现效果如下 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新建An ...

  4. Android自定义View学习笔记(一)

    绘制基础 参考:HenCoder Android 开发进阶: 自定义 View 1-1 绘制基础 Paint详解 参考:HenCoder Android 开发进阶: 自定义 View 1-2 Pain ...

  5. Android之自定义View的实现

    对于学习Android开发的小童鞋对于自定义View一定不会陌生,相信大家对它是又爱又恨,爱它可以跟随我们的心意设计出漂亮的效果:恨它想要完全流畅掌握,需要一定的功夫.对于初学者来说确实很不容易,网上 ...

  6. Android自定义View基础

    自定义控件, 视频教程 http://www.jikexueyuan.com/course/1748.html 1. 编写自定义view 2. 加入逻辑线程 3. 提取和封装自定义view 4. 利用 ...

  7. 《Android进阶之光》--View体系与自定义View

    No1: View的滑动 1)layout()方法的 public class CustomView extends View{ private int lastX; private int last ...

  8. Android自定义view控件

    转载自: http://blog.163.com/ppy2790@126/blog/static/103242241201382210910473/ 开发自定义控件的步骤: 1.了解View的工作原理 ...

  9. 自定义View的实现流程

    1.继承View组件,比如,LabelView继承了View   2.重写两个构造方法,比如,对于自定义View LabelView   LabelView(Context context),如果该自 ...

随机推荐

  1. [Angular] Modify User Provided UI with Angular Content Directives

    If we’re going to make our toggle accessible, we’ll need to apply certain aria attributes to the con ...

  2. Spring4.0MVC学习资料,注解自己主动扫描bean,自己主动注入bean(二)

    Spring4.0的新特性我们在上一章已经介绍过了. 包含它对jdk8的支持,Groovy Bean Definition DSL的支持.核心容器功能的改进,Web开发改进.測试框架改进等等.这张我们 ...

  3. 深入浅出Redis(二)高级特性:事务

    第一篇中介绍了Redis是一个强大的键-值仓储,支持五种灵活的数据结构.其实,Redis还支持其他的一些高级特性:事务.公布与订阅.管道.脚本等,本篇我们来看一下事务. 前一篇中我们提到,在Redis ...

  4. js 时钟特效

      时钟特效 CreateTime--2018年2月24日15:11:23 Author:Marydon 实现方式:都是基于HTML5的canvas标签实现的 款式一 借助jQuery插件实现 < ...

  5. JSONObjectWithData方法里options參数选择解释

    NSJSONReadingMutableContainers  Specifies that arrays and dictionaries are created as mutable object ...

  6. 菜鸟Sublime日记

            一.进行系统安装:www.sublimetext.com/3   选择相应的操作系统,你会发现安装速度惊人的快. 二.安装完成以后,先安装两个基本的插件package control ...

  7. Sql数据库查询语言

    1.概述 Sql是一种面向数据库的结构化查询语言.是符合美国国家标准化组织ANSI的一种计算机标准语言. Sql具对数据库的操作有:增删改查.创建数据库.创建表.创建存储过程.创建视图等 RDBMS关 ...

  8. redis-3.0.3安装測试

    $ tar xzvf redis-3.0.3.tar.gz $ cd redis-3.0.3 $ make     //编译 编译完毕进行 $ make test 命令測试 得到例如以下错误信息: c ...

  9. 一个JS引发的跨域问题

    忽然遇上跨域错误. 我们有张页面,使用了EXT.js,在本地运行正常,部署到服务器上,出不来数据.F12调试,提示有跨域错误? XMLHttpRequest cannot load http://19 ...

  10. jquery获取兄弟元素

    按照w3c school的指引,jquery中,要获得一个元素的兄弟,可以用 prev().next()两种方法.顾名思义,prev()获得前一个,next()获得后面一个. 问题是,如果存在前后兄弟 ...