View的改变和动画执行的背后都是在作Matrix的计算,经过必定规则改变Matrix矩阵的值,将改变后的数据反应在视图上就行成了View的展现,因此在自定义View的过程当中能够将不少关于坐标和动画的过程用Matrix实现,不过安卓提供了不少方法简化了功能,将Matrix推至幕后工做。canvas
三、使用Matrix实现View动画数组
缩放反应在坐标上的效果就是每一个像素的坐标(x,y)按照必定规则变大或缩小即造成缩放效果,每一个点的计算公式为:bash
x = k1 * x0
Y = k2 * y0 复制代码
根据变换公示就是将坐标(x、y、z)分别乘以缩放系数,若是按照上面的矩阵MSCALE_X、MSACALE_Y表示缩放,将乘积关系使用矩阵表示为原坐标矩阵 X 缩放矩阵,其实这里的就是数学中的矩阵知识,看到最后的结果便可退到出所乘的矩阵app
位移在坐标上的体现就是在同方向上全部的点的坐标同时加上或减小相同的数据,实现试图的总体平移,公式中都只是在基础上加上移动的参数,由MTRANS_X、MTRANS_Y控制,矩阵乘积以下:ide
旋转相对意位移和缩放来讲复杂一点,但也是有章可循,试想一下若是个你一个直线或一个点,旋转必定角度后计算此时的坐标位置,相信全部人都会想到利用正弦和余弦函数,以旋转不变的长度为半径便可算出(x,y),这也是Matrix控制旋转的原理,公式以下:函数
上面的过程就是公示变换,公式忘记的能够自行百度,公式转换的矩阵:post
错切:其实当第一次听到它时彻底想像不出是什么效果,可看了效果图后发现名字很形象,就是控制一个坐标的位置不变,而后修改另外一轴的坐标,效果上造成被一个角平行拉动的效果优化
x = x0 + k * y0
Y = y0复制代码
矩阵表示动画
val bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)
canvas?.drawBitmap(bitmap, matrix, paint) //绘制基本的Bitmap
canvas?.translate(0f, 200f)
val matrix = Matrix()
matrix.preScale(2f,2f) //缩放2倍
canvas?.drawBitmap(bitmap, matrix, paint)
canvas?.translate(0f, 300f)
val matrixT = Matrix()
matrixT.preRotate(90f) //旋转90度
canvas?.drawBitmap(bitmap, matrixT, paint)
canvas?.translate(0f, 300f)
val matrixR = Matrix()
matrixR.preTranslate(100f,0f) //位移
canvas?.drawBitmap(bitmap, matrixR, paint)
canvas?.translate(0f, 300f)
val matrixS = Matrix()
matrixS.preSkew(0.5f,0f) //X轴方向错切
canvas?.drawBitmap(bitmap, matrixS, paint)复制代码
使用效果ui
val matrix = Matrix()
matrix.postScale(2f, 2f) // S * M
matrix.postRotate(100f) // R * ( S * M ) = R * S * M = R * S
val matrix = Matrix()
matrix.preRotate(100f) // M * R
matrix.preScale(2f,2f) // M * R * S = R * S (与上面一致)复制代码
Matrix matrix = new Matrix();
matrix.preTranslate(pivotX,pivotY);
matrix.preRotate(angle);
......
matrix.preTranslate(-pivotX, -pivotY);复制代码
Matrix matrix = new Matrix();
// 各类操做,旋转,缩放,错切等,能够执行屡次。
matrix.postTranslate(pivotX,pivotY);
matrix.preTranslate(-pivotX, -pivotY);复制代码
Log.e("=======",matrix.toString())
Log.e("=======",matrix.toShortString())
2019-04-09 13:11:05.292 12097-12097/? E/=======: Matrix{[2.0, 0.0, 0.0][0.0, 2.0, 0.0][0.0, 0.0, 1.0]}
2019-04-09 13:11:05.292 12097-12097/? E/=======: [2.0, 0.0, 0.0][0.0, 2.0, 0.0][0.0, 0.0, 1.0]复制代码
val values = floatArrayOf(2.0f, 0.0f, 0.0f,0.0f, 2.0f, 0.0f,0.0f, 0.0f, 1.0f)
matrix.setValues(values)
//效果至关于:matrix.preScale(2f,2f)复制代码
float[] pts = new float[]{0, 0, 80, 100, 400, 300};
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f); //将X轴坐标缩小一倍
matrix.mapPoints(pts); //输出pts中结果:[0.0, 0.0, 40.0, 100.0, 200.0, 300.0]复制代码
RectF rect = new RectF(400, 400, 1000, 800);
boolean result = matrix.mapRect(rect);
复制代码
float[] src = new float[]{1000, 800};
float[] dst = new float[2];
Matrix matrix = new Matrix();
matrix.setScale(0.5f, 1f);
matrix.postTranslate(100,100);
matrix.mapVectors(dst, src); //输出结果:[500.0, 800.0] ,平移无效
Log.i(TAG, "mapVectors: "+Arrays.toString(dst));
matrix.mapPoints(dst, src); //输出结构:[600.0, 900.0]
Log.i(TAG, "mapPoints: "+Arrays.toString(dst));复制代码
(1)src:原始数组 src [x,y],存储内容为一组点
(2)srcIndex:原始数组开始位置
(3)dst:目标数组 dst [x,y],存储内容为一组点
(4)dstIndex:目标数组开始位置
(5)pointCount:控制点数量:0~4;设置控制点越多,则可操做性越大
(1)控制一个点:一张纸一个图钉智能实现评移效果,订在哪是哪
(2)控制两个点:实现旋转功能;一张纸两个钉能够将纸斜着钉
(3)控制三个点:实现错切
(4)控制四个点:千奇百怪的图形
bitmap = BitmapFactory.decodeResource(context?.resources, R.drawable.image)
val src = floatArrayOf(0f,0f, //原始定点位置数组
bitmap!!.width.toFloat(),0f,
bitmap!!.width.toFloat(),bitmap!!.height.toFloat(),
0f,bitmap!!.height.toFloat())
val dst = floatArrayOf(0f,0f,
bitmap!!.width.toFloat(),0f,
bitmap!!.width.toFloat() - 1500 ,bitmap!!.height.toFloat() - 800, //修改目标集合的坐标值
0f,bitmap!!.height.toFloat())
matrixPaint.setPolyToPoly(src,0,dst,0,4) //设置源数据集合、目标集合、控制点个数
matrixPaint.postScale(0.3f,0.3f) // 设置缩放系数复制代码
使用效果
camera.translate(x, 0, 0);
matrix.postTranslate(x, 0);复制代码
Camera camera = new Camera();
camera.translate(0, 100, 0); //Camera沿Y轴正向位移100,向上
Matrix matrix = new Matrix();
camera.getMatrix(matrix); //获取当前位置的矩阵信息(移动后的信息)
matrix.postTranslate(0,100); //Matrix沿Y轴正向位移100 (互相抵消,回到原点)复制代码
(1)、当View和摄像机在同一直线上时,沿Z轴位移的效果:近大远小
(2)、当View和摄像机不在同一直线上时,沿Z轴位移的效果:在缩小的同时靠近摄像机的投影位置(视线相交)
void rotateX (float deg);
void rotateY (float deg);
void rotateZ (float deg);
matrix?.postTranslate(centerX.toFloat(), centerY.toFloat()) //利用Matrix设置旋转的中心
matrix?.preTranslate(-centerX.toFloat(), -centerY.toFloat())复制代码
camera.setLocation(1,0,-8);
camera2.translate(-72,0,0); //两者相等复制代码
class RotateAnimation : Animation {
var centerX = 0 //设置旋转的中心坐标
var centerY = 0
var fromDegree = 0f //设置开始和结束的角度
var toDegree = 0f //设置旋转的角度
var translateZ = 0f //Z轴旋转
var currentDegree = 0f //当前角度
val camera = Camera()
var matrix: Matrix? = null
constructor(centerX: Int, centerY: Int, fromDegree: Float, toDegree: Float, translateZ: Float) {
this.centerX = centerX
this.centerY = centerY
this.fromDegree = fromDegree
this.toDegree = toDegree
this.translateZ = translateZ
}
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
super.applyTransformation(interpolatedTime, t)
//根据差值器执行进度计算当前角度
currentDegree = (toDegree - fromDegree) * interpolatedTime + fromDegree
matrix = t?.matrix //获取此时旋转的矩阵信息
camera.save()
camera.translate(0f, 0f, translateZ * interpolatedTime) //设置旋转时的Z轴位移
camera.rotateY(currentDegree) //设置旋转角度
camera.getMatrix(matrix)
camera.restore()
//利用Matrix设置旋转的中心
matrix?.postTranslate(centerX.toFloat(), centerY.toFloat())
matrix?.preTranslate(-centerX.toFloat(), -centerY.toFloat())
}
}复制代码
imageView.setOnClickListener {
val centerX = imageView.width / 2
val height = imageView.height / 2
val animation = RotateAnimation(centerX,height,0f,180f,50f)
animation.duration = 3000
animation.fillAfter = true
imageView.startAnimation(animation)
}复制代码