Android多點觸摸縮放圖片

jopen 9年前發布 | 1K 次閱讀 Java Android

自定義ImageView

    package com.example.test;

import android.app.Activity;  
import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.Canvas;  
import android.os.AsyncTask;  
import android.text.method.MovementMethod;  
import android.util.AttributeSet;  
import android.util.FloatMath;  
import android.util.Log;  
import android.view.MotionEvent;  
import android.view.animation.AccelerateInterpolator;  
import android.view.animation.Animation;  
import android.view.animation.Animation.AnimationListener;  
import android.view.animation.ScaleAnimation;  
import android.widget.ImageView;  

/**** 
 * 這里你要明白幾個方法執行的流程: 首先ImageView是繼承自View的子類. 
 * onLayout方法:是一個回調方法.該方法會在在View中的layout方法中執行,在執行layout方法前面會首先執行setFrame方法. 
 * layout方法: 
 * setFrame方法:判斷我們的View是否發生變化,如果發生變化,那么將最新的l,t,r,b傳遞給View,然后刷新進行動態更新UI. 
 * 并且返回ture.沒有變化返回false. 
 *  
 * invalidate方法:用于刷新當前控件, 
 */  
public class DragImageView extends ImageView {  

    private Activity mActivity;  

    private int screen_W, screen_H;// 可見屏幕的寬高度  

    private int bitmap_W, bitmap_H;// 當前圖片寬高  

    private int MAX_W, MAX_H, MIN_W, MIN_H;// 極限值  

    private int current_Top, current_Right, current_Bottom, current_Left;// 當前圖片上下左右坐標  

    private int start_Top = -1, start_Right = -1, start_Bottom = -1,  
            start_Left = -1;// 初始化默認位置.  

    private int start_x, start_y, current_x, current_y;// 觸摸位置  

    private float beforeLenght, afterLenght;// 兩觸點距離  

    private float scale_temp;// 縮放比例  

    /** 
     * 模式 NONE:無 DRAG:拖拽. ZOOM:縮放 
     *  
     * @author zhangjia 
     *  
     */  
    private enum MODE {  
        NONE, DRAG, ZOOM  

    };  

    private MODE mode = MODE.NONE;// 默認模式  

    private boolean isControl_V = false;// 垂直監控  

    private boolean isControl_H = false;// 水平監控  

    private ScaleAnimation scaleAnimation;// 縮放動畫  

    private boolean isScaleAnim = false;// 縮放動畫  

    private MyAsyncTask myAsyncTask;// 異步動畫  

    /** 構造方法 **/  
    public DragImageView(Context context) {  
        super(context);  
    }  

    public void setmActivity(Activity mActivity) {  
        this.mActivity = mActivity;  
    }  

    /** 可見屏幕寬度 **/  
    public void setScreen_W(int screen_W) {  
        this.screen_W = screen_W;  
    }  

    /** 可見屏幕高度 **/  
    public void setScreen_H(int screen_H) {  
        this.screen_H = screen_H;  
    }  

    public DragImageView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  

    /*** 
     * 設置顯示圖片 
     */  
    @Override  
    public void setImageBitmap(Bitmap bm) {  
        super.setImageBitmap(bm);  
        /** 獲取圖片寬高 **/  
        bitmap_W = bm.getWidth();  
        bitmap_H = bm.getHeight();  

        MAX_W = bitmap_W * 3;  
        MAX_H = bitmap_H * 3;  

        MIN_W = bitmap_W / 2;  
        MIN_H = bitmap_H / 2;  

    }  

    @Override  
    protected void onLayout(boolean changed, int left, int top, int right,  
            int bottom) {  
        super.onLayout(changed, left, top, right, bottom);  
        if (start_Top == -1) {  
            start_Top = top;  
            start_Left = left;  
            start_Bottom = bottom;  
            start_Right = right;  
        }  

    }  

    /*** 
     * touch 事件 
     */  
    @Override  
    public boolean onTouchEvent(MotionEvent event) {  
        /** 處理單點、多點觸摸 **/  
        switch (event.getAction() & MotionEvent.ACTION_MASK) {  
        case MotionEvent.ACTION_DOWN:  
            onTouchDown(event);  
            break;  
        // 多點觸摸  
        case MotionEvent.ACTION_POINTER_DOWN:  
            onPointerDown(event);  
            break;  

        case MotionEvent.ACTION_MOVE:  
            onTouchMove(event);  
            break;  
        case MotionEvent.ACTION_UP:  
            mode = MODE.NONE;  
            break;  

        // 多點松開  
        case MotionEvent.ACTION_POINTER_UP:  
            mode = MODE.NONE;  
            /** 執行縮放還原 **/  
            if (isScaleAnim) {  
                doScaleAnim();  
            }  
            break;  
        }  

        return true;  
    }  

    /** 按下 **/  
    void onTouchDown(MotionEvent event) {  
        mode = MODE.DRAG;  

        current_x = (int) event.getRawX();  
        current_y = (int) event.getRawY();  

        start_x = (int) event.getX();  
        start_y = current_y - this.getTop();  

    }  

    /** 兩個手指 只能放大縮小 **/  
    void onPointerDown(MotionEvent event) {  
        if (event.getPointerCount() == 2) {  
            mode = MODE.ZOOM;  
            beforeLenght = getDistance(event);// 獲取兩點的距離  
        }  
    }  

    /** 移動的處理 **/  
    void onTouchMove(MotionEvent event) {  
        int left = 0, top = 0, right = 0, bottom = 0;  
        /** 處理拖動 **/  
        if (mode == MODE.DRAG) {  

            /** 在這里要進行判斷處理,防止在drag時候越界 **/  

            /** 獲取相應的l,t,r ,b **/  
            left = current_x - start_x;  
            right = current_x + this.getWidth() - start_x;  
            top = current_y - start_y;  
            bottom = current_y - start_y + this.getHeight();  

            /** 水平進行判斷 **/  
            if (isControl_H) {  
                if (left >= 0) {  
                    left = 0;  
                    right = this.getWidth();  
                }  
                if (right <= screen_W) {  
                    left = screen_W - this.getWidth();  
                    right = screen_W;  
                }  
            } else {  
                left = this.getLeft();  
                right = this.getRight();  
            }  
            /** 垂直判斷 **/  
            if (isControl_V) {  
                if (top >= 0) {  
                    top = 0;  
                    bottom = this.getHeight();  
                }  

                if (bottom <= screen_H) {  
                    top = screen_H - this.getHeight();  
                    bottom = screen_H;  
                }  
            } else {  
                top = this.getTop();  
                bottom = this.getBottom();  
            }  
            if (isControl_H || isControl_V)  
                this.setPosition(left, top, right, bottom);  

            current_x = (int) event.getRawX();  
            current_y = (int) event.getRawY();  

        }  
        /** 處理縮放 **/  
        else if (mode == MODE.ZOOM) {  
            afterLenght = getDistance(event);// 獲取兩點的距離  
            float gapLenght = afterLenght - beforeLenght;// 變化的長度  
            if (Math.abs(gapLenght) > 5f) {  
                scale_temp = afterLenght / beforeLenght;// 求的縮放的比例  
                this.setScale(scale_temp);  
                beforeLenght = afterLenght;  
            }  
        }  
    }  

    /** 獲取兩點的距離 **/  
    float getDistance(MotionEvent event) {  
        float x = event.getX(0) - event.getX(1);  
        float y = event.getY(0) - event.getY(1);  
        return FloatMath.sqrt(x * x + y * y);  
    }  

    /** 實現處理拖動 **/  
    private void setPosition(int left, int top, int right, int bottom) {  
        this.layout(left, top, right, bottom);  
    }  

    /** 處理縮放 **/  
    void setScale(float scale) {  
        int disX = (int) (this.getWidth() * Math.abs(1 - scale)) / 4;// 獲取縮放水平距離  
        int disY = (int) (this.getHeight() * Math.abs(1 - scale)) / 4;// 獲取縮放垂直距離  

        // 放大  
        if (scale > 1 && this.getWidth() <= MAX_W) {  
            current_Left = this.getLeft() - disX;  
            current_Top = this.getTop() - disY;  
            current_Right = this.getRight() + disX;  
            current_Bottom = this.getBottom() + disY;  
            this.setFrame(current_Left, current_Top, current_Right,  
                    current_Bottom);  
            /*** 
             * 此時因為考慮到對稱,所以只做一遍判斷就可以了。 
             */  
            if (current_Top <= 0 && current_Bottom >= screen_H) {  
        //      Log.e("jj", "屏幕高度=" + this.getHeight());  
                isControl_V = true;// 開啟垂直監控  
            } else {  
                isControl_V = false;  
            }  
            if (current_Left <= 0 && current_Right >= screen_W) {  
                isControl_H = true;// 開啟水平監控  
            } else {  
                isControl_H = false;  
            }  
        }  
        // 縮小  
        else if (scale < 1 && this.getWidth() >= MIN_W) {  
            current_Left = this.getLeft() + disX;  
            current_Top = this.getTop() + disY;  
            current_Right = this.getRight() - disX;  
            current_Bottom = this.getBottom() - disY;  
            /*** 
             * 在這里要進行縮放處理 
             */  
            // 上邊越界  
            if (isControl_V && current_Top > 0) {  
                current_Top = 0;  
                current_Bottom = this.getBottom() - 2 * disY;  
                if (current_Bottom < screen_H) {  
                    current_Bottom = screen_H;  
                    isControl_V = false;// 關閉垂直監聽  
                }  
            }  
            // 下邊越界  
            if (isControl_V && current_Bottom < screen_H) {  
                current_Bottom = screen_H;  
                current_Top = this.getTop() + 2 * disY;  
                if (current_Top > 0) {  
                    current_Top = 0;  
                    isControl_V = false;// 關閉垂直監聽  
                }  
            }  
            // 左邊越界  
            if (isControl_H && current_Left >= 0) {  
                current_Left = 0;  
                current_Right = this.getRight() - 2 * disX;  
                if (current_Right <= screen_W) {  
                    current_Right = screen_W;  
                    isControl_H = false;// 關閉  
                }  
            }  
            // 右邊越界  
            if (isControl_H && current_Right <= screen_W) {  
                current_Right = screen_W;  
                current_Left = this.getLeft() + 2 * disX;  
                if (current_Left >= 0) {  
                    current_Left = 0;  
                    isControl_H = false;// 關閉  
                }  
            }  
            if (isControl_H || isControl_V) {  
                this.setFrame(current_Left, current_Top, current_Right,  
                        current_Bottom);  
            } else {  
                this.setFrame(current_Left, current_Top, current_Right,  
                        current_Bottom);  
                isScaleAnim = true;// 開啟縮放動畫  
            }  
        }  
    }  

    /*** 
     * 縮放動畫處理 
     */  
    public void doScaleAnim() {  
        myAsyncTask = new MyAsyncTask(screen_W, this.getWidth(),  
                this.getHeight());  
        myAsyncTask.setLTRB(this.getLeft(), this.getTop(), this.getRight(),  
                this.getBottom());  
        myAsyncTask.execute();  
        isScaleAnim = false;// 關閉動畫  
    }  

    /*** 
     * 回縮動畫執行 
     */  
    class MyAsyncTask extends AsyncTask<Void, Integer, Void> {  
        private int screen_W, current_Width, current_Height;  

        private int left, top, right, bottom;  

        private float scale_WH;// 寬高的比例  

        /** 當前的位置屬性 **/  
        public void setLTRB(int left, int top, int right, int bottom) {  
            this.left = left;  
            this.top = top;  
            this.right = right;  
            this.bottom = bottom;  
        }  

        private float STEP = 8f;// 步伐  
        private float step_H, step_V;// 水平步伐,垂直步伐  
        public MyAsyncTask(int screen_W, int current_Width, int current_Height) {  
            super();  
            this.screen_W = screen_W;  
            this.current_Width = current_Width;  
            this.current_Height = current_Height;  
            scale_WH = (float) current_Height / current_Width;  
            step_H = STEP;  
            step_V = scale_WH * STEP;  
        }  

        @Override  
        protected Void doInBackground(Void... params) {  
            while (current_Width <= screen_W) {  
                left -= step_H;  
                top -= step_V;  
                right += step_H;  
                bottom += step_V;  

                current_Width += 2 * step_H;  

                left = Math.max(left, start_Left);  
                top = Math.max(top, start_Top);  
                right = Math.min(right, start_Right);  
                bottom = Math.min(bottom, start_Bottom);  
                Log.e("jj", "top="+top+",bottom="+bottom+",left="+left+",right="+right);  
                onProgressUpdate(new Integer[] { left, top, right, bottom });  
                try {  
                    Thread.sleep(10);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
            return null;  
        }  

        @Override  
        protected void onProgressUpdate(final Integer... values) {  
            super.onProgressUpdate(values);  
            mActivity.runOnUiThread(new Runnable() {  
                @Override  
                public void run() {  
                    setFrame(values[0], values[1], values[2], values[3]);  
                }  
            });  
        }  
    }  
}  </pre> 


執行調用Activity

    package com.example.test;

import android.app.Activity;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.graphics.Rect;  
import android.os.Bundle;  
import android.util.DisplayMetrics;  
import android.view.ViewTreeObserver;  
import android.view.Window;  
import android.view.WindowManager;  
import android.view.ViewTreeObserver.OnGlobalLayoutListener;  
import android.widget.ImageView;  

public class Test extends Activity {  

    private int state_height;  
    private int screenWidth;  
    private int screenHeight;  
    private ViewTreeObserver viewTreeObserver;  
    private DragImageView dragImageView;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        requestWindowFeature(Window.FEATURE_NO_TITLE);  
        setContentView(R.layout.test);  
        dragImageView = (DragImageView) findViewById(R.id.img);  
        //獲取屏幕寬高  
        DisplayMetrics dm = new DisplayMetrics();  
        getWindowManager().getDefaultDisplay().getMetrics(dm);  
        screenWidth = dm.widthPixels;  
        screenHeight = dm.heightPixels;  
        //讀取圖片并且按寬度比例壓縮  
        Bitmap bitmap = BitmapUtil.ReadBitmapById(this, R.drawable.ke,screenWidth, screenHeight);  
        dragImageView.setImageBitmap(bitmap);  
        // 傳入Activity以更新縮放畫面  
        dragImageView.setmActivity(this);  
        /** 測量狀態欄高度 **/  
        viewTreeObserver = dragImageView.getViewTreeObserver();  
        viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {  

                @Override  
                public void onGlobalLayout() {  
                    if (state_height == 0) {  
                        // 獲取狀態欄高度  
                        Rect frame = new Rect();  
                        getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);  
                        state_height = frame.top;  
                        //去掉狀態欄高度  
                        dragImageView.setScreen_H(screenHeight- state_height);  
                        dragImageView.setScreen_W(screenWidth);  
                    }  
                }  
        });  
    }  
}  </pre> 


 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!