先上效果圖
創(chuàng)新互聯(lián)建站堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的清流網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
源碼
單點(diǎn)拖動(dòng)圖片對(duì)圖片進(jìn)行平移操作。雙手縮放圖片大小和旋轉(zhuǎn)圖片到一定的角度。圖片縮放的時(shí)候 不能大于最大的縮放因子和小于最小的縮放因子。大于最大縮放因子或者小于最小縮放因子需要對(duì)圖像進(jìn)行回彈。圖片旋轉(zhuǎn)的角度只能為90度的倍數(shù),不滿足90度要進(jìn)行回彈。圖片回彈要一個(gè)漸變的效果。
大體思路: 首先,Android中提供了Matrix類可以對(duì)圖像進(jìn)行處理。其次,要顯示一張圖片最容易想到的就是ImageView?;貜椧鬂u變的過程,可以通過屬性動(dòng)畫進(jìn)行設(shè)置。所以大體的思路是:繼承ImageView,重寫onTouchEvent()方法,判斷事件類型,在對(duì)應(yīng)的事件使用Matrix對(duì)圖像進(jìn)行變換。
Matrix是一個(gè)已經(jīng)封裝好的矩陣,最重要的作用就是對(duì)坐標(biāo)點(diǎn)進(jìn)行變換。
舉個(gè)栗子:
1.某個(gè)點(diǎn)(x0,y0,1)通過單位矩陣E映射得到的點(diǎn)還是(x0,y0,1)。
3.點(diǎn)(x0,y0,1)通過矩陣T映射得到的點(diǎn)就會(huì)做如下的變換
可以看到點(diǎn)(x0,y0,1)經(jīng)過T矩陣在x軸方向上平移了dx,在y軸方向上平移了dy。
通過以上的變換可以得到具體的思路: 我們維護(hù)一個(gè)圖像對(duì)應(yīng)的矩陣mCurrentMatrix,該矩陣主要是對(duì)ImageView中的圖像的各個(gè)點(diǎn)進(jìn)行映射。ImageView在容器位置擺放完成之后,置mCurrentMatrix矩陣為單位矩陣。當(dāng)onTouchEvent()方法中觸發(fā)單點(diǎn)觸控并且手指進(jìn)行平移的時(shí)候,調(diào)用矩陣mCurrentMatrix的postTranslate(dx,dy),對(duì)mCurrentMatrix進(jìn)行變換。當(dāng)手指抬起,利用變換結(jié)束后的矩陣對(duì)圖像的各個(gè)點(diǎn)進(jìn)行映射,從而得到平移變換后的圖像。同理可得,在兩只手指進(jìn)行縮放旋轉(zhuǎn)的時(shí)候,我們對(duì)矩陣mCurrentMatrix進(jìn)行各種變換,當(dāng)縮放旋轉(zhuǎn)的事件結(jié)束再利用變換完的矩陣去映射圖像的各個(gè)點(diǎn),從而得到縮放、旋轉(zhuǎn)后的圖像。
安卓自定義View進(jìn)階 - Matrix原理
安卓自定義View進(jìn)階 - Matrix詳解
首先理清事件的邏輯:
初始化圖像大小和位置
縮放圖像大小和控件大小自適應(yīng),平移圖像中心和控件中心重合
onTouchEvent()函數(shù)
平移操作
將圖像對(duì)應(yīng)的矩陣進(jìn)行變換。
縮放操作
mBoundRectF為記錄圖像邊界的矩形??s放的時(shí)候選取圖像的中心進(jìn)行縮放。
旋轉(zhuǎn)操作
旋轉(zhuǎn)的時(shí)候旋轉(zhuǎn)的旋轉(zhuǎn)中心也是圖像的中心
圖像中各個(gè)點(diǎn)的映射
調(diào)用ImageView的setImageMatrix(Matrix matrix)會(huì)讓ImageView根據(jù)設(shè)置的matrix去重新繪制圖像。
更新圖像的矩形邊界
獲得圖像的矩形,并根據(jù)矩陣映射矩形各個(gè)點(diǎn)的坐標(biāo)。
縮放回彈
旋轉(zhuǎn)回彈
一些計(jì)算方法
要求圖像的變換是一個(gè)漸變的過程,很容易想到的就是屬性動(dòng)畫。因?yàn)閷傩詣?dòng)畫本身就是對(duì)值進(jìn)行不斷set的過程。而我們維護(hù)的矩陣也是一個(gè)值,所以很自然可以想到,如果得到回彈之前的矩陣的值以及回彈之后矩陣的值,就可以根據(jù)動(dòng)畫監(jiān)聽器中動(dòng)畫當(dāng)前的系數(shù)值去改變矩陣的值。
對(duì)animator對(duì)象設(shè)置完監(jiān)聽器之后,就可以在手指抬起的時(shí)候調(diào)用屬性動(dòng)畫的start()方法開啟動(dòng)畫。
自定義可平移、縮放、旋轉(zhuǎn)的控件主要點(diǎn)有兩個(gè)方面:一是onTouchEvent()中判斷平移、旋轉(zhuǎn)、縮放的觸發(fā)條件,平移位移量、縮放比例因子、旋轉(zhuǎn)角度的計(jì)算。二是Matrix矩陣的應(yīng)用。
橫屏180°旋轉(zhuǎn)系統(tǒng)不會(huì)回調(diào)到到 onConfigurationChanged() ,只能使用其他的方案,目前有2個(gè)方案
1、使用 OrientationEventListener 監(jiān)聽屏幕的旋轉(zhuǎn),里面本質(zhì)使用的是 TYPE_ACCELEROMETER 傳感器,具體如下:
開啟調(diào)用 mOrientationListener. enable() , 關(guān)閉調(diào)用 mOrientationListener. disable() ;這種方式對(duì)性能消耗比較大, 但是可以獲取到手機(jī)當(dāng)前的角度
2、使用監(jiān)聽 DisplayManager 方式,手機(jī)切換方向會(huì)導(dǎo)致UI 顯示的改變,所以會(huì)回調(diào)到這里
這種方式不會(huì)耗性能
設(shè)備平放,屏幕朝正上方。以下四個(gè)常量分別代表:
private static final int ROTATION_0 = 0;//初始情況。這個(gè)時(shí)候設(shè)備是橫屏還是豎屏與硬件設(shè)備安裝時(shí)默認(rèn)的顯示方向有關(guān)。
private static final int ROTATION_90 = 1;//設(shè)置屏幕方向自動(dòng)旋轉(zhuǎn)后,右側(cè)翻起側(cè)立時(shí),屏幕會(huì)旋轉(zhuǎn)到這個(gè)方向。
private static final int ROTATION_270 = 2;//設(shè)置屏幕方向自動(dòng)旋轉(zhuǎn)后,左側(cè)翻起度側(cè)立時(shí),屏幕會(huì)旋轉(zhuǎn)到這個(gè)方向。
private static final int ROTATION_180 = 3;//設(shè)置屏幕方向自動(dòng)旋轉(zhuǎn)后,屏幕底部側(cè)立時(shí),屏幕會(huì)旋轉(zhuǎn)到這個(gè)方向。
再看兩個(gè)數(shù)組:
view plain
private static final int[][][] THRESHOLDS_WITH_180 = new int[][][] {
{{60, 165}, {165, 195}, {195, 300}},
{{0, 30}, {165, 195}, {195, 315}, {315, 360}},
{{0, 45}, {45, 165}, {165, 195}, {330, 360}},
{{0, 45}, {45, 135}, {225, 315}, {315, 360}},
};
private static final int[][] ROTATE_TO_WITH_180 = new int[][] {
{ROTATION_90, ROTATION_180, ROTATION_270},
{ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0},
{ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},
{ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_0},
};
當(dāng)前屏幕旋轉(zhuǎn)方向?yàn)镽OTATION_0時(shí),取int[][] threshold=THRESHOLDS_WITH_180[0];
當(dāng)前屏幕旋轉(zhuǎn)方向?yàn)镽OTATION_90時(shí),取int[][] threshold=THRESHOLDS_WITH_180[1];
當(dāng)前屏幕旋轉(zhuǎn)方向?yàn)镽OTATION_270時(shí),取int[][] threshold=THRESHOLDS_WITH_180[2];
當(dāng)前屏幕旋轉(zhuǎn)方向?yàn)镽OTATION_180時(shí),取int[][] threshold=THRESHOLDS_WITH_180[3];
其中,threshold中的每一個(gè)元素由兩個(gè)值構(gòu)成,用來表示一個(gè)范圍。
WindowOrientationListener會(huì)注冊(cè)一個(gè)Accelerator類型的SensorEventListener,當(dāng)有新的SensorEvent產(chǎn)生時(shí),調(diào)用filterOrientation產(chǎn)生一個(gè)int orientation值。這個(gè)值會(huì)在threshold的各個(gè)元素表示的范圍中匹配,看會(huì)落在哪個(gè)范圍。假設(shè)當(dāng)前屏幕方向?yàn)镽OTATION_0,那么threshold={{60, 165}, {165, 195}, {195, 300}},假設(shè)這個(gè)時(shí)候把屏幕左側(cè)翻起90度。filterOrientation計(jì)算出的orientation值落在了第三個(gè)元素范圍內(nèi),那么去ROTATE_TO_WITH_180中尋找與它對(duì)應(yīng)的值,發(fā)現(xiàn)是ROTATION_270,那么就把當(dāng)前屏幕旋轉(zhuǎn)方向改變?yōu)?70度。threshold的取值就變成了THRESHOLDS_WITH_180[2]。當(dāng)把屏幕再次放平時(shí),filterOrientation計(jì)算出的orientation值會(huì)落在第一個(gè)元素表示的范圍內(nèi)。去ROTATE_TO_WITH_180中尋找與它對(duì)應(yīng)的值,發(fā)現(xiàn)是ROTATION_0,那么當(dāng)前屏幕旋轉(zhuǎn)方向被改變?yōu)?度。
還有一個(gè)變量比較重要,mAllow180Rotation,這個(gè)變量設(shè)置為false時(shí),就不使用THRESHOLDS_WITH_180和ROTATE_TO_WITH_180這一對(duì)數(shù)組來做上面這些變的了,就使用THRESHOLDS和ROTATE_TO。
其實(shí),我研究了半天也沒有搞清filterOrientation的算法以及THRESHOLDS_WITH_180和THRESHOLDS這兩個(gè)數(shù)組里面的每個(gè)數(shù)字代表的具體意義。最后只搞清了上面的這個(gè)流程,還有ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_180這四個(gè)角度分別代表哪四個(gè)方向。但這足以應(yīng)付我們要做的事情了。
比如,我想讓屏幕最多只旋轉(zhuǎn)90度和180度,不讓它有旋轉(zhuǎn)270度的機(jī)會(huì)。那就把ROTATE_TO_WITH_180里面的ROTATION_270全部變成90度。這樣,應(yīng)該旋轉(zhuǎn)到270度時(shí),就會(huì)旋轉(zhuǎn)到90度了。如果不想讓屏幕旋轉(zhuǎn),把所有值都改成ROTATION_0就可以了。
再深入挖掘一下這個(gè)話題
PhonwWindowManager是唯一實(shí)現(xiàn)WindowOrientationListener接口的類,它管理著整個(gè)設(shè)備界面的顯示。當(dāng)PhonwWindowManager通過WindowOrientationListener知道屏幕方向發(fā)生旋轉(zhuǎn)時(shí),會(huì)告訴WindowManagerService:
mWindowManager.setRotation(rotation, false, mFancyRotationAnimation);
而WindowManagerService得到這個(gè)通知后,會(huì)做兩個(gè)比較重要的事情:
1、Surface.setOrientation(0, rotation, animFlags);
2、mRotationWatchers.get(i).onRotationChanged(rotation);
我們知道,每個(gè)Activity都有一個(gè)View樹,每個(gè)View樹都是繪畫在一個(gè)Surface上面的。通過上面這兩步,先把Surface給旋轉(zhuǎn)了,再告訴Activity重新繪制View樹,就完了整個(gè)屏幕的旋轉(zhuǎn)。
當(dāng)前文章:android旋轉(zhuǎn),Android旋轉(zhuǎn)框
轉(zhuǎn)載來于:http://jinyejixie.com/article14/dsecdge.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、建站公司、電子商務(wù)、品牌網(wǎng)站制作、網(wǎng)站排名、動(dòng)態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
移動(dòng)網(wǎng)站建設(shè)知識(shí)