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)
}複製代碼