自定义View中处理简单的拖拽及缩放事件。
因为经常需要使用到,所以花时间整理了简单的用法,及给出Demo。以后再用到方面直接上手。
其中往边界拖拽时会有回弹的效果
其中用到了组件
1、Scroller 用于View能够平滑滚动,配合重写computeScroll()完成
2、ScaleGestureDetector 缩放手势类,捕捉双手指放大缩小事件
3、GestureDetector 普通手势类,处理移动,点击,双击等事件,示例中只使用了拖动事件
4、Matrix 矩阵,配合Canvas能够对View放大缩小,平移等变形
package xyz.wbsite.wbui;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.Scroller;
public class MyView extends View implements View.OnTouchListener {
private Scroller scroller = new Scroller(getContext());
private ScaleGestureDetector scaleGestureDetector;
private GestureDetector gestureDetector;
private Matrix matrix;
private Paint paint;
private float scale = 1.0f;
private int dX = 0;
private int dY = 0;
private int width = 500;
private int height = 500;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化
matrix = new Matrix();
scaleGestureDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.OnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
//记录缩放参数,留在onDraw中处理变形
scale = scale * detector.getScaleFactor();
invalidate();
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
invalidate();
}
});
gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//记录平移参数,留在onDraw中处理变形
dX += -distanceX;
dY += -distanceY;
System.out.println("distanceX" + -distanceX + "," + dX);
invalidate();
return true;
}
});
paint = new Paint();
paint.setColor(Color.RED);
this.setOnTouchListener(this);
}
@Override
public boolean performClick() {
return super.performClick();
}
@Override
protected void onDraw(Canvas canvas) {
//组合缩放及平移参数,其中set、pre、post区别可以自行查找资料
matrix.setScale(scale, scale);
matrix.postTranslate(dX, dY);
canvas.concat(matrix);
//这边绘制自己的图形
canvas.drawRect(0, 0, width, height, paint);
}
@Override
public void computeScroll() {
super.computeScroll();
if (scroller.computeScrollOffset()) {
dX = scroller.getCurrX();
dY = scroller.getCurrY();
System.out.println("computeScroll=" + dX);
postInvalidate();
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
if (!scroller.isFinished()) {
scroller.abortAnimation();
}
}
break;
case MotionEvent.ACTION_UP: {//抬起时,计算回弹,以左上角的点为准,在一个矩形中,如果不在则回弹到这个矩形的边界。保证视图可见。
int minX = (int) (getMeasuredWidth() < scale * width ? getMeasuredWidth() - scale * width : 0);
int minY = (int) (getMeasuredHeight() < scale * height ? getMeasuredHeight() - scale * height : 0);
int maxX = (int) (getMeasuredWidth() < scale * width ? 0 : getMeasuredWidth() - scale * width);
int maxY = (int) (getMeasuredHeight() < scale * height ? 0 : getMeasuredHeight() - scale * height);
Rect rect = new Rect(minX, minY, maxX, maxY);
if (!rect.contains(dX, dY)) {
int dx = 0;
int dy = 0;
if (dX < minX) {
dx = minX - dX;
} else if (dX > maxX) {
dx = maxX - dX;
}
if (dY < minY) {
dy = minY - dY;
} else if (dY > maxY) {
dy = maxY - dY;
}
System.out.println("dX=" + dX + ",dY=" + dY + ";dx=" + dx + ",dy=" + dy);
scroller.startScroll(dX, dY, dx, dy);
postInvalidate();
}
}
break;
}
scaleGestureDetector.onTouchEvent(event);
gestureDetector.onTouchEvent(event);
return true;
}
}