Android開(kāi)發(fā)之圖片旋轉(zhuǎn)功能實(shí)現(xiàn)方法【基于Matrix】
本文實(shí)例講述了Android開(kāi)發(fā)之圖片旋轉(zhuǎn)功能實(shí)現(xiàn)方法。分享給大家供大家參考,具體如下:
在Android中進(jìn)行圖像旋轉(zhuǎn)需要使用Matrix,它包含了一個(gè)3*3的矩陣,專門用于進(jìn)行圖像變換匹配。Matrix ,中文里叫矩陣,高等數(shù)學(xué)里有介紹,在圖像處理方面,主要是用于平面的縮放、平移、旋轉(zhuǎn)等操作。Matrix沒(méi)有機(jī)構(gòu)體,它必須初始化,然后通過(guò)reset方法和set方法來(lái)實(shí)現(xiàn)。
首先介紹一下矩陣運(yùn)算。加法和減法就不用說(shuō)了,太簡(jiǎn)單了,對(duì)應(yīng)位相加就好。圖像處理,主要用到的是乘法 。下面是一個(gè)乘法的公式:

在 Android 里面, Matrix 由 9 個(gè) float 值構(gòu)成,是一個(gè) 3*3 的矩陣。如下圖。

沒(méi)專業(yè)工具,畫的挺難看。解釋一下,上面的 sinX 和 cosX ,表示旋轉(zhuǎn)角度的 cos 值和 sin 值,注意,旋轉(zhuǎn)角度是按順時(shí)針?lè)较蛴?jì)算的。 translateX 和 translateY 表示 x 和 y 的平移量。 scale 是縮放的比例, 1 是不變, 2 是表示縮放 1/2,這樣子。
Matrix的操作,總共分為translate(平移),rotate(旋轉(zhuǎn)),scale(縮放)和skew(傾斜)四種,每一種變換在Android的API里都提供了set,post和pre三種操作方式,除了translate,其他三種操作都可以指定中心點(diǎn)。set是直接設(shè)置Matrix的值,每次set一次,整個(gè)Matrix的數(shù)組都會(huì)變掉。
我們現(xiàn)在通過(guò)setRotate設(shè)置旋轉(zhuǎn)角度,用creatBitmap創(chuàng)建一個(gè)經(jīng)過(guò)旋轉(zhuǎn)等處理的Bitmap對(duì)象,然后將Bitmap繪制到屏幕之上,于是就實(shí)現(xiàn)了旋轉(zhuǎn)操作。
下面使用一個(gè)示例來(lái)說(shuō)明Matix的使用以及旋轉(zhuǎn)的方式及運(yùn)行效果。
package cn.edu.pku;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
public class PictureRotateActivity extends Activity {
/** Called when the activity is first created. */
private GameRotateView1 gameview = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameview = new GameRotateView1(this);
setContentView(gameview);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if ( gameview == null )
{
return false;
}
if ( keyCode == KeyEvent.KEYCODE_BACK)
{
this.finish();
return true;
}
return gameview.onKeyDown(keyCode,event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
super.onKeyUp(keyCode, event);
return true;
}
}
具體圖像旋轉(zhuǎn)處理代碼如下:
package cn.edu.pku;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
public class GameRotateView1 extends View implements Runnable {
Bitmap bitmap = null;
int bitmapWidth = 0;
int bitmapHeight = 0;
float angle = 0.0f;
Matrix matrix = new Matrix();
public GameRotateView1(Context context) {
super(context);
// TODO Auto-generated constructor stub
setFocusableInTouchMode(true); //設(shè)置可以捕捉鍵盤事件
//獲取圖像資源
bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.cute)).getBitmap();
bitmapWidth = bitmap.getWidth();
bitmapHeight = bitmap.getHeight();
new Thread(this).start();
}
public void run() {
// TODO Auto-generated method stub
while(!Thread.currentThread().isInterrupted()){
try{
Thread.sleep(100);
}catch (InterruptedException e) {
// TODO: handle exception
Thread.currentThread().interrupt();
}
postInvalidate(); //可以直接在線程中更新界面
}
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
matrix.reset();
matrix.setRotate(angle); //設(shè)置旋轉(zhuǎn)
//按照matrix的旋轉(zhuǎn)構(gòu)建新的Bitmap
Bitmap bitmapcute = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, true);
//繪制旋轉(zhuǎn)之后的圖像
GameRotateView1.DrawImage(canvas, bitmapcute, (320 - bitmapWidth)/2, 10);
bitmapcute = null;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
angle--;
}else if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
angle++;
}
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
// TODO Auto-generated method stub
return true;
}
/**
* 繪制一個(gè)Bitmap
* canvas 畫布
* bitmap 圖片
* x 屏幕上的x坐標(biāo)
* y 屏幕上的y坐標(biāo)
*/
public static void DrawImage(Canvas canvas, Bitmap _bitmap, int x, int y)
{
/* 繪制圖像 */
canvas.drawBitmap(_bitmap, x, y, null);
}
最后我們通過(guò)鍵盤的左右鍵可以實(shí)現(xiàn)圖像的選裝,在這里實(shí)現(xiàn)的圖像的右旋轉(zhuǎn):

更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android圖形與圖像處理技巧總結(jié)》、《Android開(kāi)發(fā)入門與進(jìn)階教程》、《Android調(diào)試技巧與常見(jiàn)問(wèn)題解決方法匯總》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
相關(guān)文章
Android編程設(shè)計(jì)模式之抽象工廠模式詳解
這篇文章主要介紹了Android編程設(shè)計(jì)模式之抽象工廠模式,結(jié)合實(shí)例形式詳細(xì)分析了Android抽象工廠模式的概念、原理、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-12-12
Android系統(tǒng)設(shè)置中的清除數(shù)據(jù)會(huì)清除哪些數(shù)據(jù)?
這篇文章主要介紹了Android系統(tǒng)設(shè)置中的清除數(shù)據(jù)會(huì)清除哪些數(shù)據(jù)?本文對(duì)比了清除前和清除后的數(shù)據(jù)情況,從而得出到底清除了哪些數(shù)據(jù),需要的朋友可以參考下2015-01-01
Android平臺(tái)基于Pull方式對(duì)XML文件解析與寫入方法詳解
這篇文章主要介紹了Android平臺(tái)基于Pull方式對(duì)XML文件解析與寫入方法,結(jié)合實(shí)例形式分析了Android基于Pull方式對(duì)xml文件解析及寫入操作的步驟、原理與操作技巧,需要的朋友可以參考下2016-10-10
Android實(shí)現(xiàn)四級(jí)聯(lián)動(dòng)地址選擇器
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)四級(jí)聯(lián)動(dòng)地址選擇器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10
Android PreferenceActivity與PreferenceFragment詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了Android PreferenceActivity與PreferenceFragment詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2016-12-12
Android 組件Gallery和GridView示例講解
本文主要講解Android 組件Gallery和GridView,這里詳細(xì)介紹組件Gallery和GridView的知識(shí)要點(diǎn),并附示例代碼和實(shí)現(xiàn)效果圖,有興趣的小伙伴可以參考下2016-08-08
android基于SwipeRefreshLayout實(shí)現(xiàn)類QQ的側(cè)滑刪除
本篇文章主要介紹了android基于SwipeRefreshLayout實(shí)現(xiàn)類QQ的側(cè)滑刪除,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-10-10
Android 多線程實(shí)現(xiàn)重復(fù)啟動(dòng)與停止的服務(wù)
這篇文章主要介紹了Android 多線程實(shí)現(xiàn)重復(fù)啟動(dòng)與停止的服務(wù)的相關(guān)資料,多線程環(huán)境下為了避免死鎖,一般提倡開(kāi)放調(diào)用,開(kāi)放調(diào)用可以避免死鎖,它的代價(jià)是失去原子性,這里說(shuō)明重復(fù)啟動(dòng)與停止的服務(wù),需要的朋友可以參考下2017-08-08
android開(kāi)發(fā)教程之卸載sd卡對(duì)MediaServer的處理
Android中如果MediaServer訪問(wèn)SD卡上的音頻文件,卸載SD卡的時(shí)候,就會(huì)kill掉MediaServer,卸載SD卡上必要條件就是沒(méi)有進(jìn)程訪問(wèn)SD卡上的資源文件。Kill掉MediaServer的進(jìn)程后,MediaServer會(huì)重新啟動(dòng)。2014-02-02

