图片是一张长图,在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()方法