Android中實現雙指縮放的功能

Android中實現雙指縮放的功能

安卓中實現將圖片縮放的功能提供了一個很好的類:ScaleGestureDetector,本章就介紹使用canvas和ScaleGestureDetector類實現縮放的功能,如果要想詳細瞭解ScaleGestureDetector請參考博文Android的ScaleGestureDetector縮放類詳解
1. 先初始化縮放比和圖片居中繪製的座標點

	float posX, posY;										//圖片的座標
    int viewWidth, viewHeight;								//屏幕的寬高
    float widthScale, heightScale;							//寬高縮放比
    boolean hasInitViewSize;								//是否已經初始化視圖

    public void initSize() {
        viewWidth = getWidth();								//得到屏幕寬度
        viewHeight = getHeight();							//得到屏幕高度
        if (viewWidth < 0 && viewHeight < 0) {
            return;
        }
        hasInitViewSize = true;
        widthScale = viewWidth / imgWidth;					//寬高縮放比=屏幕的寬高/屏幕的寬高
        heightScale = viewHeight / imgHeight;
        scaleFactor = Math.min(widthScale, heightScale);	//總縮放比取寬高縮放比中最小的
        posX = viewWidth / 2 - imgWidth / 2;				//使圖片居中繪製
        posY = viewHeight / 2 - imgHeight / 2;
    }

2. 創建兩個內部類分別繼承SimpleOnScaleGestureListener和SimpleOnGestureListener來動態獲取縮放比和座標

class MySimpleOnGestureDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            posX -= distanceX;		//X軸的座標=X軸的座標-在X軸方向的移動距離
            posY -= distanceY;		//y軸的座標=y軸的座標-在y軸方向的移動距離
            invalidate();			//刷新view
            return true;
        }
    }

    class MySimpleScaleOnGestureDetector extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scaleFactor *= detector.getScaleFactor();		//縮放比=縮放比*動態獲取的縮放比
            scaleFactor = scaleFactor < 0.75 ? (float) 0.75 : scaleFactor > 3 ? 3 : scaleFactor;	//控制縮放倍率在0.75-3之間
            invalidate();		//刷新view
            return true;
        }
    }

3. 爲了移動圖片時不超出屏幕,還得進行控制,原則是:圖片較小時任意一條邊都不能出了邊界,圖片較大任意一條邊都不能進入邊界。寬度和高度分別獨立計算。

public void checkBounds() {
        if (scaleFactor > widthScale) {	//寬度方向已經填滿
            posX = Math.min(posX, (scaleFactor - 1) * (imgWidth / 2));
            posX = Math.max(posX, viewWidth - imgWidth - (scaleFactor - 1) * (imgWidth / 2));
        } else {
            posX = Math.max(posX, (scaleFactor - 1) * (imgWidth / 2));
            posX = Math.min(posX, viewWidth - imgWidth - (scaleFactor - 1) * (imgWidth / 2));
        }
        if (scaleFactor > heightScale) {	//高度方向已經填滿
            posY = Math.min(posY, (scaleFactor - 1) * (imgHeight / 2));
            posY = Math.max(posY, viewHeight - imgHeight - (scaleFactor - 1) * (imgHeight / 2));
        } else {
            posY = Math.max(posY, (scaleFactor - 1) * (imgHeight / 2));
            posY = Math.min(posY, viewHeight - imgHeight - (scaleFactor - 1) * (imgHeight / 2));
        }
    }

4. 在類中實現onDraw方法進行繪製縮放

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap == null) {
            return;
        }
        if (!hasInitViewSize) {
            initSize();
        }
        canvas.save();	//畫布保存
        checkBounds();	//檢查邊界,使圖片不能超出屏幕
        canvas.scale(scaleFactor, scaleFactor, posX + imgWidth / 2, posY + imgHeight / 2);	///以圖片的中心爲基點進行縮放
        canvas.drawBitmap(bitmap, posX, posY, paint);	//繪製圖片
        canvas.restore();	//畫布重繪
    }

5. 關鍵點已經差不多寫完了,現在將完整的類寫上

package com.example.mygesture;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

public class MyScaleView extends View {
    ScaleGestureDetector scaleGestureDetector;
    float scaleFactor;
    float posX, posY;
    int viewWidth, viewHeight;
    float widthScale, heightScale;
    boolean hasInitViewSize;
    Paint paint = new Paint();
    Bitmap bitmap;
    float imgWidth, imgHeight;
    GestureDetector gestureDetector;

    public MyScaleView(Context context, @Nullable AttributeSet attrs) {	//注意:得在有兩個參數的構造函數中實例化ScaleGestureDetector 和GestureDetector 
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        scaleGestureDetector = new ScaleGestureDetector(context, new MySimpleScaleOnGestureDetector());
        gestureDetector = new GestureDetector(context, new MySimpleOnGestureDetector());
    }

    class MySimpleOnGestureDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            posX -= distanceX;
            posY -= distanceY;
            invalidate();
            return true;
        }
    }

    class MySimpleScaleOnGestureDetector extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scaleFactor *= detector.getScaleFactor();
            scaleFactor = scaleFactor < 0.75 ? (float) 0.75 : scaleFactor > 3 ? 3 : scaleFactor;
            invalidate();
            return true;
        }
    }

    public void initSize() {
        viewWidth = getWidth();
        viewHeight = getHeight();
        if (viewWidth < 0 && viewHeight < 0) {
            return;
        }
        hasInitViewSize = true;
        widthScale = viewWidth / imgWidth;
        heightScale = viewHeight / imgHeight;
        scaleFactor = Math.min(widthScale, heightScale);
        posX = viewWidth / 2 - imgWidth / 2;
        posY = viewHeight / 2 - imgHeight / 2;
    }

    public void checkBounds() {				//檢查邊界
        if (scaleFactor > widthScale) {
            posX = Math.min(posX, (scaleFactor - 1) * (imgWidth / 2));
            posX = Math.max(posX, viewWidth - imgWidth - (scaleFactor - 1) * (imgWidth / 2));
        } else {
            posX = Math.max(posX, (scaleFactor - 1) * (imgWidth / 2));
            posX = Math.min(posX, viewWidth - imgWidth - (scaleFactor - 1) * (imgWidth / 2));
        }
        if (scaleFactor > heightScale) {
            posY = Math.min(posY, (scaleFactor - 1) * (imgHeight / 2));
            posY = Math.max(posY, viewHeight - imgHeight - (scaleFactor - 1) * (imgHeight / 2));
        } else {
            posY = Math.max(posY, (scaleFactor - 1) * (imgHeight / 2));
            posY = Math.min(posY, viewHeight - imgHeight - (scaleFactor - 1) * (imgHeight / 2));
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        scaleGestureDetector.onTouchEvent(event);	//雙指縮放
        gestureDetector.onTouchEvent(event);		//單指移動
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap == null) {
            return;
        }
        if (!hasInitViewSize) {
            initSize();
        }
        canvas.save();
        checkBounds();
        canvas.scale(scaleFactor, scaleFactor, posX + imgWidth / 2, posY + imgHeight / 2);
        canvas.drawBitmap(bitmap, posX, posY, paint);
        canvas.restore();
    }

    public void setImageResouse(int resID) {	//設置圖片
        bitmap = BitmapFactory.decodeResource(getResources(), resID);
        imgWidth = bitmap.getWidth();
        imgHeight = bitmap.getHeight();
        initSize();
        invalidate();
    }
}

6. 類已經寫好了,現在對其使用,創建一個新的Activity

6.1 構造佈局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".text.Main8Activity">

    <com.example.mygesture.MyScaleView
        android:id="@+id/activity_main8_myScaleView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

6.2 對應的類中

package com.example.mygesture.text;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.example.mygesture.MyScaleView;
import com.example.mygesture.R;

public class Main8Activity extends AppCompatActivity {
    MyScaleView myScaleView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main8);
        myScaleView = findViewById(R.id.activity_main8_myScaleView);
        myScaleView.setImageResouse(R.drawable.q4);
    }
}

7. 所以使用還是很簡單的,因爲縮放操作模擬器上不好演示,效果圖就省略了。

Tip: 小白,寫得不好請見諒。若有不對的地方請留言。

關於手勢方面的功能點還可以參考Android中實現自定義手勢和識別手勢的功能Android中簡單實現頁面翻轉和自動翻轉的功能

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章