android scrollview内实现图片的手势缩放

图片是一张长图,在scrollview内上下滑动图片的同时,增加了对图片的手势放大或缩小的操作。

之前将手势缩放的布局放在scrollview内总是会发生手势冲突,这个不会,可以找张图片试试。

主界面的activity:

package test;
import com.agehua.drag.R;

import android.app.Activity; 
import android.content.Context;
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Matrix; 
import android.graphics.PointF; 
import android.hardware.SensorManager; 
import android.os.Bundle; 
import android.util.DisplayMetrics;
import android.util.FloatMath; 
import android.util.Log; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.View.OnTouchListener; 
import android.widget.Button; 
import android.widget.ImageView; 

public class Touch extends Activity implements OnTouchListener, OnClickListener { 
	private static final String TAG = "Touch" ; 

	// These matrices will be used to move and zoom image 
	Matrix matrix = new Matrix(); 
	Matrix savedMatrix = new Matrix(); 
	PointF start = new PointF(); 
	PointF mid = new PointF(); 
	float  oldDist; 
	private ImageView view; 
	private MyScrollView scrollView;
	private Button zoomIn, zoomOut; 
	//button zoom 
	private float scaleWidth = 1; 
	private float scaleHeight = 1; 
	private Bitmap bmp, zoomedBMP; 

	private static final double ZOOM_IN_SCALE = 1.25;//放大系数 
	private static final double ZOOM_OUT_SCALE = 0.8;//缩小系数 
	// We can be in one of these 3 states 
	static final int NONE = 0; 
	static final int DRAG = 1; 
	static final int ZOOM = 2; 
	int mode = NONE; 

	int bmpWidth,bmpHeight;
	int imageHeight, imageWidth;

	@Override 
	public void onCreate(Bundle savedInstanceState) { 
		super.onCreate(savedInstanceState); 
		setContentView(R.layout.main1); 
		view = (ImageView) findViewById(R.id.imageView); 
		view.setOnTouchListener(this); 
		scrollView = (MyScrollView)findViewById(R.id.scrollview);

		zoomIn = (Button)findViewById(R.id.btn_zoom_in);
		zoomOut = (Button)findViewById(R.id.btn_zoom_out);
		zoomOut.setOnClickListener(this);
		zoomIn.setOnClickListener(this);
		//取得drawable中图片,放大,缩小,多点触摸的作用对象 
		bmp = BitmapFactory.decodeResource(Touch.this.getResources(), R.drawable.aaa); 
		bmpWidth = bmp.getWidth(); 
		bmpHeight = bmp.getHeight(); 
	} 


	public boolean onTouch(View v, MotionEvent event) { 
		// Handle touch events here... 
		ImageView view = (ImageView) v; 

//		imageWidth = v.getWidth();//屏幕宽度(像素数)
//		imageHeight = v.getHeight();

		// Handle touch events here... 
		switch (event.getAction() & MotionEvent.ACTION_MASK) { 
		//设置拖拉模式 
		case MotionEvent.ACTION_DOWN: 
			savedMatrix.set(matrix); 
			start.set(event.getX(), event.getY()); 
			Log.d(TAG, "mode=DRAG" ); 
			mode = DRAG; 
			break; 

		case MotionEvent.ACTION_UP: 
		case MotionEvent.ACTION_POINTER_UP: 
			mode = NONE; 
			Log.d(TAG, "mode=NONE" ); 
			break; 
			//设置多点触摸模式 
		case MotionEvent.ACTION_POINTER_DOWN: 
			oldDist = spacing(event); 
			//			originalDist = oldDist;
			Log.d(TAG, "oldDist=" + oldDist); 
			if (oldDist > 10f) { 
				savedMatrix.set(matrix); 
				midPoint(mid, event); 
				mode = ZOOM; 
				Log.d(TAG, "mode=ZOOM" ); 
			} 
			break; 
			//若为DRAG模式,则点击移动图片 
		case MotionEvent.ACTION_MOVE: 
			if (mode == DRAG) { 
				matrix.set(savedMatrix); 
				// 设置位移 
				matrix.postTranslate(event.getX() - start.x, 
						event.getY() - start.y); 
			} 
			//若为ZOOM模式,则多点触摸缩放 
			else if (mode == ZOOM) { 
				float newDist = spacing(event); 
				Log.d(TAG, "newDist=" + newDist); 
				if (newDist > 10f) { 
					matrix.set(savedMatrix); 
					float scale = newDist / oldDist; 
					//设置缩放比例和图片中点位置 
					matrix.postScale(scale, scale, mid.x, mid.y); 
				} 
			} 
			break; 
		} 

		// Perform the transformation 
		view.setImageMatrix(matrix); 

		return true; // indicate event was handled 
	} 
	
	
	
	//计算移动距离 
	private float spacing(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 midPoint(PointF point, MotionEvent event) { 
		float x = event.getX(0) + event.getX(1); 
		float y = event.getY(0) + event.getY(1); 
		point.set(x / 2, y / 2); 
	} 

	//放大,缩小按钮点击事件 
	@Override 
	public void onClick(View v) { 
		if(v == zoomIn){ 
			enlarge(); 
		}else if (v == zoomOut) { 
			small(); 
		} 
	} 

	//按钮点击缩小函数 
	private void small() { 
		int bmpWidth = bmp.getWidth(); 
		int bmpHeight = bmp.getHeight(); 

		scaleWidth = (float) (scaleWidth * ZOOM_OUT_SCALE); 
		scaleHeight = (float) (scaleHeight * ZOOM_OUT_SCALE); 

		Matrix matrix = new Matrix(); 
		matrix.postScale(scaleWidth, scaleHeight); 
		zoomedBMP = Bitmap.createBitmap(bmp, 0, 0, bmpWidth, bmpHeight, matrix, 
				true); 
		view.setImageBitmap(zoomedBMP); 
	} 

	//按钮点击放大函数 
	private void enlarge() { 
		try { 
			int bmpWidth = bmp.getWidth(); 
			int bmpHeight = bmp.getHeight(); 

			scaleWidth = (float) (scaleWidth * ZOOM_IN_SCALE); 
			scaleHeight = (float) (scaleHeight * ZOOM_IN_SCALE); 

			Matrix matrix = new Matrix(); 
			matrix.postScale(scaleWidth, scaleHeight); 
			zoomedBMP = Bitmap.createBitmap(bmp, 0, 0, bmpWidth, bmpHeight, matrix, 
					true); 
			view.setImageBitmap(zoomedBMP); //存在内存溢出问题

		} catch (Exception e) { 
			//can't zoom because of memory issue, just ignore, no big deal 
		} 
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		if (null != bmp && !bmp.isRecycled()) {
			bmp.recycle();
		}
		System.gc();
		super.onDestroy();
	} 


}

 scrollview部分的代码:

package test;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;

public class MyScrollView extends ScrollView {
	private boolean canScroll;

	private GestureDetector mGestureDetector;
	View.OnTouchListener mGestureListener;

	public MyScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mGestureDetector = new GestureDetector(context, new YScrollDetector());
		canScroll = true;
	}
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		if(ev.getAction() == MotionEvent.ACTION_UP)
			canScroll = true;
		return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
	}

	public class YScrollDetector extends SimpleOnGestureListener {
		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
			if(canScroll)
				if (Math.abs(distanceY) >= Math.abs(distanceX))
					canScroll = true;
				else
					canScroll = false;
			return canScroll;
		}
	}
}

  

main1.xml内容为:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center" 
    android:orientation="vertical">

    <test.MyScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal"
        android:orientation="vertical" 
        android:layout_weight="1"
        android:id="@+id/scrollview">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="matrix"
            android:src="@drawable/aaa" />
    </test.MyScrollView>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center_horizontal" >

        <Button
            android:id="@+id/btn_zoom_in"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="放大" />

        <Button
            android:id="@+id/btn_zoom_out"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="缩小" />
    </LinearLayout>

</LinearLayout>

注意问题:1.scrollview的layout_width属性最好设置为match_parent,如果设置为wrap_content,图片会滑动不到屏幕边界。

                  2.imageview的scaleType属性一定要设置为matrix(矩阵模式),否则不能实现手势缩放。

                  3.不用按钮,直接手势放大缩放也基本能满足需求,这里只是作为方法记录下来。 

还有一些存在问题,1.放大缩小均未做限制;

                                2.点击按钮放大的时候,会有内存溢出的异常出现,问题应该是出现在setImageBitmap方法上。

续:

       使用一个开源jar包PhotoView,可以完美实现图片缩小,手指松开后,图片又弹回到原图大小的效果。

       该项目网址:https://github.com/chrisbanes/PhotoView     

       PhotoView使用起来非常简单,只要两步:

       1.在初始化PhotoViewAttacher的时候传入要缩放图片的ImageView

       2.在mImageView调用setImageDrawable、setImageBitmap、setImageResource之类的方法后,调用PhotoViewAttacher的update()方法

                  

相关推荐