Android變形(Transform)之Camera使用介紹
引言
接Android變形(Transform)之Matrix,來總結(jié)下Camera的使用,Camera主要實現(xiàn)3D的變形,有轉(zhuǎn)動,旋轉(zhuǎn)等,Camera的源碼是由Native(本地代碼)實現(xiàn),提供的接口也比較簡單。官方的介紹:A camera instance can be used to compute 3D transformations and generate a matrix that can be applied, for instance, on a Canvas
.
效果圖
原圖:
變形以后:
API使用
Camera提供的方法如下:
save:保存當(dāng)前狀態(tài)
restore:回復(fù)當(dāng)前狀態(tài)
translate:在x,y,z三位控件內(nèi)進行平移
rotateX:以(0.0)為中心,繞X軸進行選擇
rotateY:以(0.0)為中心,繞Y軸進行選擇
rotateZ:以(0.0)為中心,旋轉(zhuǎn)(此處和Matrix旋轉(zhuǎn)原理一樣,只不過反向相反,為逆時針)
...
常用的就這么多
實踐
直接上代碼:
public class CameraTransformView extends View {
private Bitmap mBitmap;
private Camera mCamera;
private Matrix mMatrix;
private int deltaX, deltaY, deltaZ, extraZ;
private int centerX, centerY;
public CameraTransformView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setDrawable(int resId) {
mBitmap = BitmapFactory.decodeResource(getResources(), resId);
centerX = mBitmap.getWidth() / 2;
centerY = mBitmap.getHeight() / 2;
mCamera = new Camera();
mMatrix = new Matrix();
}
public void setDelta(int x, int y, int z, int extra) {
deltaX += x;
deltaY += y;
deltaZ += z;
extraZ += extra;
invalidate();
}
public void reset() {
deltaX = 0;
deltaY = 0;
deltaZ = 0;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
mCamera.save();
mCamera.translate(10, 10, extraZ);
mCamera.rotateX(deltaX);
mCamera.rotateY(deltaY);
mCamera.rotateZ(deltaZ);
mCamera.getMatrix(mMatrix);
mCamera.restore();
mMatrix.preTranslate(-this.centerX, -this.centerY);
mMatrix.postTranslate(this.centerX, this.centerY);
canvas.drawBitmap(mBitmap, mMatrix, null);
super.onDraw(canvas);
}
}
其實Camera的變化就是封裝了一個Matrix矩陣,可以通過getMatrix方法來獲取這個坐標(biāo)矩陣。在上面的Demo中就用到了該方法做些額外的處理,下面具體看看:
@Override
protected void onDraw(Canvas canvas) {
mCamera.save();
mCamera.translate(10, 10, extraZ);
mCamera.rotateX(deltaX);
mCamera.rotateY(deltaY);
mCamera.rotateZ(deltaZ);
mCamera.getMatrix(mMatrix);
mCamera.restore();
//mMatrix.preTranslate(-this.centerX, -this.centerY);
//mMatrix.postTranslate(this.centerX, this.centerY);
canvas.drawBitmap(mBitmap, mMatrix, null);
super.onDraw(canvas);
}
在onDraw方法中,可以通過Camera的方法來完成變形。注意11,12行,如果在onDraw的時候不進行倆行設(shè)置的話,可以看到效果如下:
可以看到,其按照Y軸旋轉(zhuǎn)中心點是(0,0),那么平常的應(yīng)用而言,大多希望其中心點在圖片的中心點上。所以需要加入
mMatrix.preTranslate(-this.centerX, -this.centerY);
mMatrix.postTranslate(this.centerX, this.centerY);
其實這一節(jié)的重點就在于剖析這倆句話。
從Camara的API中可以看出來其不提供變形中心點的設(shè)置方法,那么怎么辦呢,基本思路是:假設(shè)圖片中心點為(centerX,centerY),既然Camera始終以(0,0)為中心點,那么我先將圖形矩陣往左移動centerX,再往上移動centerY,讓(centerX,centerY)正好掐在初始的(0,0)上,這樣進行變形的話,中心點就變成了(centerX,centerY),達(dá)到了目的,當(dāng)然這還沒結(jié)束,你既然偏移了(-centerX,-centerY),那么變形以后得移回來,然后再往右下方分別移動centerX,centerY。
按照矩陣的變換,可以表達(dá)為:
1,0,-centerX 1,0,centerX
0,1,-centerY * 變形矩陣 * 0,1,centerY
0,0,1 0,0,1
那么具體就如此,思路和代碼結(jié)合起來怎么來解釋呢,接著看,我們需要回顧下Matrix中的部分知識。
回顧
Matrix提供的三種變形方式為:set,post,pre。
set就是先reset,然后進行變形
pre可以解釋為先乘,在矩陣原理中對應(yīng)的右乘
post可以理解成后乘,在矩陣遠(yuǎn)離中對應(yīng)左乘
不著急,接下倆具體看什么是先乘,后乘,什么是左乘,右乘。
舉個例子:
原圖
讓一個圖形按照中心點放大至2倍
那么期望的效果是:中心點不變(圖片被邊緣截斷了)
那么按照之前提高的思路:假設(shè)中心點是(50,50)先左上移50,也即(-50,-50)再進行放大,再右下移50,也即(50,50)
api調(diào)用即為:setScale(2,2), preTranslate(-50,-50), postTranslate(50,50)
照例來說對應(yīng)矩陣為:
1,0,-50 2,0,0 1,0,50 2,0,50
0,1,-50 * 0,0,2 * 0,1,50 = 0,2,50
0,0,1 0,0,1 0,0,1 0,0,1
可以看到結(jié)果是放大至2倍,但是卻往右下移動了(50,50),奇怪要是這樣的話,和預(yù)期的效果圖一樣預(yù)期的效果圖矩陣應(yīng)該為(方法至2倍,往左上移動(-50,-50))
2,0,-50
0,2,-50,
0,0,1
好,揭曉下疑點:
此處api的執(zhí)行順序為:preTranslate(-50,-50) -> setScale(2,2) -> postTranslate(50,50) 沒有問題
答案揭曉:矩陣符合變化的原則,如果圖形經(jīng)過F1,F2...Fn此變形,對應(yīng)矩陣為T1,T2...Tn,符合矩陣T = Tn*Tn-1...*T1
那么正確的矩陣算法應(yīng)該為
1,0,50 2,0,0 1,0,-50 2,0,-50
0,1,50 * 0,0,2 * 0,1,-50 = 0,2,-50
0,0,1 0,0,1 0,0,1 0,0,1
此處也解釋了pre為右乘,post為左乘的原理了。
那么到此為止,一切都都得到了解釋。
回歸
回歸到Camera的Demo當(dāng)中,既然Camera的變形中心點是(0,0),而且Camera的變形實際是對Matrix的變形,我們可以通過getMatrix方法來獲取這個Matrix,然后通過左移pre,變形后右移post來實現(xiàn)中心點的設(shè)置。
相關(guān)文章
AndroidManifest.xml <uses-feature>和<uses-permisstio
這篇文章主要介紹了AndroidManifest.xml <uses-feature>和<uses-permisstion>分析及比較的相關(guān)資料,需要的朋友可以參考下2017-06-06Android優(yōu)化查詢加載大數(shù)量的本地相冊圖片
本文介紹了Android優(yōu)化查詢加載大數(shù)量的本地相冊圖片,可以方便的照片的查詢,,感興趣的小伙伴們可以參考一下。2016-10-10android開發(fā)教程之使用looper處理消息隊列
這篇文章主要介紹了通過HandlerThread對象來實現(xiàn)使用looper處理消息隊列的功能,大家參考使用吧2014-01-01Flutter 封裝一個 Banner 輪播圖效果的實例代碼
這篇文章主要介紹了Flutter 封裝一個 Banner 輪播圖效果,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07Flutter 使用cached_image_network優(yōu)化圖片加載體驗
在 Flutter 中,cached_image_network 即提供了緩存網(wǎng)絡(luò)圖片功能,同時還提供了豐富的加載過程指示。本文就來看下cached_image_network的具體使用2021-05-05