1.效果
1.拖拽
2.双击复原、双指缩放
3.点击回调、关闭activity
2.监听手势实现功能
- 双指缩放
- 拖拽移动
- 点击事件回调(查看大图的Activity中可以finish)
- 双击事件回调,图片复原
3.用法及代码详解
3.1属性添加
/res/value/attrs.xml添加属性节点
<declare-styleable name="ScaleImageView">
<attr name="img_src" format="reference" />
</declare-styleable>
3.2xml布局文件中使用
留意使用自定义属性
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.cupster.base_super_resource.gesturedetector.ScaleImageView
android:id="@+id/tv_words"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="120dp"
android:minWidth="120dp"
app:img_src="@mipmap/pic_drinking"
android:layout_centerInParent="true"
/>
</RelativeLayout>
3.3Activity使用
public class ScaleGesTureActivity extends AppCompatActivity implements ScaleImageView.OperateListener{
ScaleImageView mTvGesture;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gesture_detector);
mTvGesture = findViewById(R.id.tv_words);
mTvGesture.setOperateListener( this);
}
@Override
public void onClicked() {
finish();
}
@Override
public void onDoubleClicked() {
}
}
3.4ScaleImageView详解
package com.cupster.base_super_resource.gesturedetector;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;
import com.cupster.base_super_resource.R;
public class ScaleImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener, GestureDetector.OnDoubleTapListener,GestureDetector.OnGestureListener {
private ScaleGestureDetector scaleGestureDetector;
private GestureDetector gestureDetector;
Bitmap mBitmap; // 图片
RectF mBitmapRectF; // 图片所在区域
Matrix mBitmapMatrix; // 控制图片的 matrix
/**
* 图片宽度
*/
private int mBitmapWidth;
/**
* 图片高度
*/
private int mBitmapHeight;
/**
* 控件宽度
*/
private int mWidth;
/**
* 控件高度
*/
private int mHeight;
boolean canDrag = false;
PointF lastPoint = new PointF(0, 0);
public ScaleImageView(Context context) {
this(context, null);
}
public ScaleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
BitmapFactory.Options options = new BitmapFactory.Options();
options.outWidth = 960/2;
options.outHeight = 800/2;
mDeafultPaint = new Paint();
TypedArray typedArray = context.obtainStyledAttributes(attrs ,R.styleable.ScaleImageView);
int resId = typedArray.getResourceId(R.styleable.ScaleImageView_img_src , R.mipmap.ic_launcher);
typedArray.recycle();
mBitmap = BitmapFactory.decodeResource(this.getResources(), resId, options);
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
mBitmapRectF = new RectF(0,0,mBitmap.getWidth(), mBitmap.getHeight());
mBitmapMatrix = new Matrix();
scaleGestureDetector = new ScaleGestureDetector(context, this);
gestureDetector = new GestureDetector(context ,this);
gestureDetector.setIsLongpressEnabled(true);
gestureDetector.setOnDoubleTapListener(this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mWidth = getWidth();
mHeight = getHeight();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
scaleGestureDetector.onTouchEvent(event);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// 是否第一个手指 && 点是否在图片内
if (event.getPointerId(event.getActionIndex()) == 0 && mBitmapRectF.contains((int)event.getX(), (int)event.getY())){
canDrag = true;
lastPoint.set(event.getX(), event.getY());
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// 是否第一个手指
if (event.getPointerId(event.getActionIndex()) == 0){
canDrag = false;
}
break;
case MotionEvent.ACTION_MOVE:
// 如果存在第一个手指,且这个手指点在图片内,则拖动绘制
if (canDrag) {
int index = event.findPointerIndex(0);
mBitmapMatrix.postTranslate(event.getX(index)-lastPoint.x, event.getY(index)-lastPoint.y);
lastPoint.set(event.getX(index), event.getY(index));
mBitmapRectF = new RectF(0,0,mBitmap.getWidth(), mBitmap.getHeight());
mBitmapMatrix.mapRect(mBitmapRectF);
invalidate();
}
break;
}
return true;
}
Paint mDeafultPaint;
boolean isFirstDraw = true;
@Override
protected void onDraw(Canvas canvas) {
if (isFirstDraw){//初始位置居中
isFirstDraw = false;
mBitmapMatrix.setScale(1.0f,1.0f , mBitmapWidth /2 , mBitmapHeight /2);
mBitmapMatrix.setTranslate(mWidth/2 - mBitmapWidth /2,mHeight/2 - mBitmapHeight /2);
mBitmapRectF = new RectF(0,0,mBitmap.getWidth(), mBitmap.getHeight());
mBitmapMatrix.mapRect(mBitmapRectF);
}
canvas.drawBitmap(mBitmap, mBitmapMatrix, mDeafultPaint);
}
float mScale = 1.0f;
float mMaxScale = mScale * 8.0f;
float mMinScale = mScale * 0.5f;
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (mBitmap == null) {
return true;
}
// 缩放因子
float scaleFactor = detector.getScaleFactor();
// 已经缩放值
float scale = getmScale();
float scaleResult = scale * scaleFactor;
if (scaleResult >= mMaxScale && scaleFactor > 1.0f)
scaleFactor = mMaxScale / scale;
if (scaleResult <= mMinScale && scaleFactor < 1.0f)
scaleFactor = mMinScale / scale;
mBitmapMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
setImageMatrix(mBitmapMatrix);
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
float scale = getmScale();
if (scale < mScale) {
mBitmapMatrix.postScale(mScale / scale, mScale / scale, mWidth / 2, mHeight / 2);
setImageMatrix(mBitmapMatrix);
}
}
/**
* 当前缩放的值
*/
private float getmScale() {
float[] floats = new float[9];
mBitmapMatrix.getValues(floats);
return floats[Matrix.MSCALE_X];
}
public interface OperateListener {
void onClicked();
void onDoubleClicked();
}
OperateListener operateListener;
public void setOperateListener(OperateListener operateListener) {
this.operateListener = operateListener;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {//单击事件回调
if (operateListener != null){
operateListener.onClicked();
}
return true;
}
@Override
public boolean onDoubleTap(MotionEvent motionEvent) {
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent motionEvent) {//双击事件回调,回调2次
if (operateListener != null){
operateListener.onDoubleClicked();
}
isFirstDraw =true;
invalidate();
return true;
}
@Override
public boolean onDown(MotionEvent motionEvent) {//按下那一刻
return true;
}
@Override
public void onShowPress(MotionEvent motionEvent) {
}
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return false;
}
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
return false;
}
@Override
public void onLongPress(MotionEvent motionEvent) {
}
@Override
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
return false;
}
}