好久没有更新自己的简书博客了,说来真是惭愧,感觉自己太点懒了。话说其实坚持写博客还是很有用的,可以梳理自己的知识,帮助自己加深印象,找工作的时候也算是一点筹码,起码能够说明热爱技术并且真的有涉及过,而不是整天在公司混日子,所以今后我应该会增加博客的更新频率。接下来是正题。
事故现场
最近在对公司项目中的控件进行优化改造,其中一个是能够上拉和下拉的弹性ScrollView。
发现没有,当使用一个手指的时候感觉还不错。但是当我想用两个手指交替不断下拉想要把视图内容往下“扒”的时候就办不到了,因为他在onTouchEvent()方法里只是最简单的实现了下拉的逻辑而没有涉及到多指触控,而我想要的效果是像QQ空间或者微信朋友圈那样的。
注意在第二个手指按下,第一个手指抬起时,此时原本的第二个手指会被识别为第一个,所以图片会直接跳动到第二个手指位置。原因是event.getX()和event.getY中没有传入pointerIndex的参数, 那么默认追踪的就是pointerIndex = 0的手指,当第二个手指按下,第一个手指抬起的时候,触发了move事件,event.getX()和event.getY()此时是获取第二个手指的数据,而lastPoint.x和lastPoint.y并没有在第二个手指按下的时候进行更新,记录的是第一个手指抬起时候的坐标,和evet.getX()、event.getY()有较大的距离, 所以postTranslate了很大一段距离, 发生了跳动的情况。
为了不出现这种情况,我们可以判断一下 pointId 并且只获取第一个手指的数据,这样就能避免这种情况发生了,如下。
针对多指触控处理后版本:
public class DragViewUpGrade extends View {
String TAG = "DragViewUpGrade";
Bitmap mBitmap; // 图片
RectF mBitmapRectF; // 图片所在区域
Matrix mBitmapMatrix; // 控制图片的 matrix
boolean canDrag = false;
PointF lastPoint = new PointF(0, 0);
public DragViewUpGrade(Context context) {
this(context, null);
}
public DragViewUpGrade(Context context, AttributeSet attrs) {
super(context, attrs);
mDeafultPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
BitmapFactory.Options options = new BitmapFactory.Options();
options.outWidth = 960/2;
options.outHeight = 800/2;
mBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.poly_test, options);
mBitmapRectF = new RectF(0,0,mBitmap.getWidth(), mBitmap.getHeight());
mBitmapMatrix = new Matrix();
}
@Override
public boolean onTouchEvent(MotionEvent 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) {
// ▼ 注意 getX 和 getY
// 只找第一根手指
int index = event.findPointerIndex(0);
// Log.i(TAG, "index="+index);
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;
}
private Paint mDeafultPaint;
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, mBitmapMatrix, mDeafultPaint);
}
}
这个也是GcsSloop的代码,因为这里只追踪第一根手指(pointerId = 0的手指),第二根手指的活动全都无视,所以不会再出现跳动的情况
github地址
最后是国际惯例,给出demo的github地址MutiTouchDemo
网友评论
因为action_up只能监控到最后一个手指的抬起
所以只需要添加对 MotionEvent.ACTION_POINTER_UP 的监控就行了吧(其他的都不需要变)