2011-11-29

在 Android 裡使用 Matrix 旋轉圖片

主角是 Matrix,除了將圖片旋轉外,還可以移位、放大或變形。

main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
    <LinearLayout
      android:orientation="horizontal"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center_horizontal"
      >
      <Button
          android:id="@+id/clockwise"
          android:layout_width="wrap_content" 
          android:layout_height="wrap_content"
          android:text="順時針"
          android:onClick="onClick"
          />
      <Button
          android:id="@+id/counterClockwise"
          android:layout_width="wrap_content" 
          android:layout_height="wrap_content"
          android:text="逆時針"
          android:onClick="onClick"
          />
      <Button
          android:id="@+id/turnRight"
          android:layout_width="wrap_content" 
          android:layout_height="wrap_content"
          android:text="右轉"
          android:onClick="onClick"
          />
      <Button
          android:id="@+id/turnLeft"
          android:layout_width="wrap_content" 
          android:layout_height="wrap_content"
          android:text="左轉"
          android:onClick="onClick"
          />
    </LinearLayout>
  <TextView
      android:id="@+id/tv"
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content"
      android:gravity="center_horizontal"
      />
  <ImageView
      android:id="@+id/img"
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent"
      android:src="@drawable/arrow"
      android:scaleType="matrix" 
      />
</LinearLayout>
MatrixActivity
public class MatrixActivity extends Activity {

    private static String TAG = "MatrixActivity";
    private ImageView img;
    private float screenCenterX;
    private float screenCenterY;
    private Matrix matrix;
    private TextView tv;
    private int angle;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        this.img = (ImageView) this.findViewById(R.id.img);
        
        // 將圖片移到螢幕中心點
        // 先取得螢幕尺寸
        Display display = this.getWindowManager().getDefaultDisplay();
        float screenWidth = display.getWidth();
        float screenHeight = display.getHeight() - 60;
        this.insert2Tv("螢幕尺寸:" + screenWidth + " x " + screenHeight);

        // 計算螢幕中心點供後續旋轉使用
        this.screenCenterX = screenWidth / 2f;
        this.screenCenterY = screenHeight / 2f;
        this.insert2Tv("螢幕中心點:" + screenCenterX + " x " + screenCenterY);

        // 取得圖片尺寸
        Drawable d = this.getResources().getDrawable(R.id.img);
        int imgWidth = d.getIntrinsicWidth();
        int imgHeight = d.getIntrinsicHeight();
        this.insert2Tv("圖片尺寸:" + imgWidth + " x " + imgHeight);

        // 算出圖片位於螢幕中心點的左上角座標
        float imgX = (screenWidth - imgWidth) / 2f;
        float imgY = (screenHeight - imgHeight) / 2f;
        this.insert2Tv("圖片座標:" + imgX + " x " + imgY);

        // 使用 Matrix 移動圖片
        this.matrix = new Matrix();
        this.matrix.postTranslate(imgX, imgY);
        // 一定要這個才會生效
        this.img.setImageMatrix(this.matrix);
        this.insert2Tv("onCreated");
    }

    public void onClick(View v) {
        final int targetAngle = this.angle;
        final int reverseTargetAngle;
        if (targetAngle >= 0) {
            reverseTargetAngle = targetAngle - 360;
        }
        else {
            reverseTargetAngle = targetAngle + 360;
        }
        this.insert2Tv("順向目標角度:" + targetAngle);
        this.insert2Tv("逆向目標角度:" + reverseTargetAngle);
        switch (v.getId()) {
        case R.id.clockwise:
            new Handler() {

                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    matrix.postRotate(30, screenCenterX, screenCenterY);
                    // 一定要這個才會生效
                    img.setImageMatrix(matrix);
                    angle += 30;
                    insert2Tv("目前角度:" + angle);
                    if (angle % 360 != targetAngle
                            && angle % 360 != reverseTargetAngle) {
                        this.sendMessageDelayed(this.obtainMessage(), 100);
                    }
                    else {
                        angle = targetAngle;
                    }
                }
            }.sendEmptyMessage(0);
            break;
        case R.id.counterClockwise:
            new Handler() {

                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    matrix.postRotate(-30, screenCenterX, screenCenterY);
                    // 一定要這個才會生效
                    img.setImageMatrix(matrix);
                    angle -= 30;
                    insert2Tv("目前角度:" + angle);
                    if (angle % 360 != targetAngle
                            && angle % 360 != reverseTargetAngle) {
                        this.sendMessageDelayed(this.obtainMessage(), 100);
                    }
                    else {
                        angle = targetAngle;
                    }
                }
            }.sendEmptyMessage(0);
            break;
        case R.id.turnRight:
            this.matrix.postRotate(10, this.screenCenterX, this.screenCenterY);

            // 一定要這個才會生效

            this.img.setImageMatrix(matrix);
            this.angle += 10;
            insert2Tv("目前角度:" + angle);
            break;
        case R.id.turnLeft:
            this.matrix.postRotate(-10, this.screenCenterX, this.screenCenterY);


            // 一定要這個才會生效


            this.img.setImageMatrix(matrix);
            this.angle -= 10;
            insert2Tv("目前角度:" + angle);
            break;
        }
    }

    private void insert2Tv(String msg) {
        if (this.tv == null) {
            this.tv = (TextView) this.findViewById(R.id.tv);
        }
        this.tv.setText(msg);
        Log.d(TAG, msg);
    }
}

沒有留言:

張貼留言