2018年8月28日 星期二

[Android] 圖片縮放

智慧手機的兩指放大縮小功能應該沒有人不知道吧

這篇文章就是記錄一下這個功能的做法

其實所有程式都是來自於官方,也不需要做任何修改

只是做個學習記錄而已



我繼承了原生的ImageView元件

然後再修改onTouchEvent完成

依樣先來給個正姐再來頗析程式吧(雖然我知道你們只會看到這一行,嘿嘿嘿)

package com.distudio.learn.demo.touch;

import
android.content.Context;
import
android.graphics.Canvas;
import
android.graphics.drawable.Drawable;
import
android.util.AttributeSet;
import
android.view.MotionEvent;
import
android.view.ScaleGestureDetector;

import
com.distudio.learn.demo.R;

public class
ScaleWith2Fingers extends android.support.v7.widget.AppCompatImageView{
    private Drawable mIcon;
    private
ScaleGestureDetector mScaleDetector;
    private float
mScaleFactor = 1.f;

    public
ScaleWith2Fingers(Context context) {
        this(context, null, 0);
   
}

    public ScaleWith2Fingers(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
   
}

    public ScaleWith2Fingers(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
       
mIcon = context.getResources().getDrawable(R.drawable.duran);
       
mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());
       
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
   
}

    @Override
   
public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
       
canvas.save();
       
canvas.scale(mScaleFactor, mScaleFactor);
       
mIcon.draw(canvas);
       
canvas.restore();
   
}

    @Override
   
public boolean onTouchEvent(MotionEvent ev) {
        // Let the ScaleGestureDetector inspect all events.
       
mScaleDetector.onTouchEvent(ev);
        return true;
   
}

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
       
public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();

           
// Don't let the object get too small or too large.
           
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));

           
invalidate();
            return true;
       
}
    }
}

步驟說明:
1. 先建立一個基本的View,把已知的都填上去吧
其中mScaleFactor是用來調整縮放大小的值,很重要
在onDraw使用下列方式調整大小
canvas.scale(mScaleFactormScaleFactor)


public class ScaleWith2Fingers extends android.support.v7.widget.AppCompatImageView{
    private Drawable mIcon;
    private float
mScaleFactor = 1.f;

    public
ScaleWith2Fingers(Context context) {
        this(context, null, 0);
   
}

    public ScaleWith2Fingers(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
   
}

    public ScaleWith2Fingers(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
       
mIcon = context.getResources().getDrawable(R.drawable.duran);
       
mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());
   
}

    @Override
   
public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
       
canvas.save();
       
canvas.scale(mScaleFactor, mScaleFactor);
       
mIcon.draw(canvas);
       
canvas.restore();
   
}
}

2. 然後建立一個private class繼承SimpleOnScaleGestureListener

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
   
public boolean onScale(ScaleGestureDetector detector) {
        mScaleFactor *= detector.getScaleFactor();

       
// Don't let the object get too small or too large.
       
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));

       
invalidate();
        return true;
   
}
}

重點來了!!SimpleOnScaleGestureListener是用來監聽縮放事件的方法

裡面什麼都沒做,需要子類別來實作他

裡面有三個方法可以實作,分別是onScale、onScaleBegin、onScaleEnd

Public methods

booleanonScale(ScaleGestureDetector detector)
Responds to scaling events for a gesture in progress.
booleanonScaleBegin(ScaleGestureDetector detector)
Responds to the beginning of a scaling gesture.
voidonScaleEnd(ScaleGestureDetector detector)
Responds to the end of a scale gesture.

這裡我們實作onScale,取得縮放的參數值後重新繪製圖片

取得縮放的參數值
mScaleFactor *= detector.getScaleFactor();

控制縮放值的大小,不要太大或太小

官方建議的,但實際上我把這行拿掉好像沒差

// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
呼叫onDraw重新繪製圖片
invalidate();

3. 監聽縮放事件以實作完成,來補充那些未完成的view程式吧

把該宣告的、該加上去的都補一補

宣告並建構ScaleGestureDetector

private ScaleGestureDetector mScaleDetector;
public ScaleWith2Fingers(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
   
mIcon = context.getResources().getDrawable(R.drawable.duran);
   
mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());
   
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}

4. Override onTouchEvent

使用我們剛剛建立的ScaleGestureDetector程式

@Override
public boolean onTouchEvent(MotionEvent ev) {
   
// Let the ScaleGestureDetector inspect all events.
    mScaleDetector.onTouchEvent(ev);
    return true;
}

如此便大功告成,XML應用方式如下


<com.distudio.learn.demo.touch.ScaleWith2Fingers
    android:layout_width="match_parent"
   
android:layout_height="match_parent" />



提供我的原始碼給大家參考
ScaleWith2Fingers.cs
ScaleWith2FingersActivity.cs
activity_scale_with_2_fingers.xml
整包下載

安裝完成之後點選中間那個『兩指縮放』就可以demo效果囉





參考資料:
https://developer.android.com/training/gestures/scale#basic-scaling-example
SimpleOnScaleGestureListener API Doc

沒有留言:

張貼留言