2014/01/02

Android ImageView實現拖曳及縮放功能

Layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.cyfang.test.MainActivity" >

    <com.cyfang.test.MyImageView
        android:id="@+id/myImageView"
        android:layout_width="480px"
        android:layout_height="400px" />

</RelativeLayout>



Activity:
package com.cyfang.test;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }
}




MyImageView:
package com.cyfang.test;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;

public class MyImageView extends ImageView {

 /** 使用者動作 */
 private enum Action {
  /** 沒動作 */
  None,
  /** 縮放 */
  Zoom,
  /** 拖曳 */
  Drag
 };

 /** 動作 */
 private Action action = Action.None;

 /** 矩形大小 */
 private RectF rectF;

 /** 畫筆 */
 private Paint paint = new Paint();

 {
  // 空心
  paint.setStyle(Paint.Style.STROKE);
  // 藍色
  paint.setColor(Color.BLUE);
 };

 /** 自訂ImageView */
 public MyImageView(Context context, AttributeSet attrs) {
  super(context, attrs);
  this.rectF = new RectF(0, 0, 480 - 50, 400 - 5);
  this.setOnTouchListener(new OnTouchListener() {

   /** 使用者點擊位置 */
   private float x, y;

   /** 距離 */
   private float distance = 1f;

   @Override
   public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
     x = event.getX();
     y = event.getY();
     action = Action.Drag;
     break;

    case MotionEvent.ACTION_POINTER_UP:
     action = Action.None;
     break;

    case MotionEvent.ACTION_POINTER_DOWN:
     distance = getDistance(event);
     // 螢幕觸碰為2個觸控點時
     if (event.getPointerCount() == 2) {
      action = Action.Zoom;
     }
     break;

    case MotionEvent.ACTION_MOVE:
     if (action == Action.Drag) {
      int moveX = (int) (event.getRawX() - x);
      int moveY = (int) (event.getRawY() - y);
      // 設定layout位置
      v.layout(moveX, moveY, moveX + v.getWidth(), moveY + v.getHeight());
     } else if (action == Action.Zoom) {

      // 距離
      float newDistance = getDistance(event);

      // 縮放比例
      float scale = newDistance / this.distance;

      // 設定當前距離
      this.distance = newDistance;

      // 將ImageView放大
      LayoutParams params = v.getLayoutParams();
      params.width = (int) (v.getWidth() * scale);
      params.height = (int) (v.getHeight() * scale);

      // 重新定義矩形大小
      rectF = new RectF(0, 0, params.width - 50, params.height - 5);
      v.setLayoutParams(params);
     }
     break;
    }

    return true;
   }
  });
 }

 // onDraw會持續渲染
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  // 畫矩形
  canvas.drawRect(rectF, paint);
 }

 /** 取距離公式 */
 private float getDistance(MotionEvent event) {
  // x點距離
  float x = event.getX(0) - event.getX(1);

  // y點距離
  float y = event.getY(0) - event.getY(1);

  return FloatMath.sqrt(x * x + y * y);
 }
}


縮放前:


縮放後:


移動前:


移動後: