android 手势控制支持平移缩放
2017-02-13 00:00
369 查看
摘要: 实现思路:通过android API 获取触摸点,记录当前以及之后的相应触摸点位置,以前一个触摸点与移动之后的触摸点相应位置的变动计算相应的向量,利用向量公式计算夹角,项目忽略旋转动作。
手势分析:在此将不动点定义为锚点(手势中心),
1、当只有一个点移动并且方向与锚点到与移动起始点连线夹角在-45°~45°或135°~225°时认为是缩放,缩放程度为移动向量在锚点与移动向量的起始点反方向上的模长除以锚点与移动点起始位置距离;当夹角大于45°时即认为时旋转(单点移动均认为是缩放)
2、当有2个点在移动时,同向(各象限以45°为界)即为平移,方向则为缩放。平移距离为两个移动向量长度均值
手势分析:在此将不动点定义为锚点(手势中心),
1、当只有一个点移动并且方向与锚点到与移动起始点连线夹角在-45°~45°或135°~225°时认为是缩放,缩放程度为移动向量在锚点与移动向量的起始点反方向上的模长除以锚点与移动点起始位置距离;当夹角大于45°时即认为时旋转(单点移动均认为是缩放)
2、当有2个点在移动时,同向(各象限以45°为界)即为平移,方向则为缩放。平移距离为两个移动向量长度均值
public class MultiTouchGestures implements OnTouchListener { private GesturesL mGesturesL; private int mTouchSlop; private SparseArray<Point> mTouchPoints; private SparseArray<Point> mTouchMovePoints; @SuppressLint("ShowToast") public MultiTouchGestures(Context c) { mTouchSlop = getTouchSlop(c); mTouchPoints = new SparseArray<Point>(5);// 通常手机不支持超过5个以上的触点 mTouchMovePoints = new SparseArray<Point>(5);// 通常手机不支持超过5个以上的触点 mGesturesL = new GesturesL(); } @SuppressLint("ClickableViewAccessibility") public boolean onTouch(View v, MotionEvent event) { try { if (event.getPointerCount() > 2) return false; switch (getAction(event)) { case MotionEvent.ACTION_DOWN: clearPoint(); Point point = getPoint(event, 0); putPoint(point.id, point); break; case MotionEvent.ACTION_MOVE: if(event.getPointerCount()<2){ return true; } if (event.getPointerCount() != mTouchPoints.size()) { initPoint(event); } mTouchMovePoints.clear(); for (int i = 0; i < event.getPointerCount(); i++) { int pointId = event.getPointerId(i); Point poi = mTouchPoints.get(pointId); if (getOffset(poi, event, i) > mTouchSlop) { mTouchMovePoints.put(poi.id, getPoint(event, i));// 查找位置发生了偏移的点 } } if (mTouchMovePoints.size() == 1) { Point poimove = mTouchMovePoints.valueAt(0); Point lastpoi = mTouchPoints.get(poimove.id); Point diff = new Point(); diff.set(poimove.x - lastpoi.x, poimove.y - lastpoi.y); Point otherPoi = getOtherPoint(lastpoi); Point line = new Point(); line.set(lastpoi.x - otherPoi.x, lastpoi.y - otherPoi.y); double diffm = Math.sqrt((Math.pow(diff.x, 2) + Math.pow(diff.y, 2))); double linem = Math.sqrt((Math.pow(line.x, 2) + Math.pow(line.y, 2))); double cos = (diff.x * line.x + diff.y * line.y) / (diffm * linem); if (Math.abs(cos) < Math.sqrt(2) / 2) {// 夹角大于45度为平移 int progress = poimove.x - lastpoi.x; mGesturesL.OnChange(getCenterPoint(poimove, otherPoi), Gestures.translation, progress, v, event);// 旋转没有方向 lastpoi.set(poimove.x, poimove.y); } else { double d0 = Math.sqrt((Math.pow(otherPoi.x - lastpoi.x, 2) + Math.pow(otherPoi.y - lastpoi.y, 2))); double d1 = Math.sqrt((Math.pow(poimove.x - otherPoi.x, 2) + Math.pow(poimove.y - otherPoi.y, 2))); double scale = 1; if (d0 != 0) scale = d1 / d0; mGesturesL.OnChange(new Point(otherPoi.x, otherPoi.y, 0), Gestures.scale, scale, v, event); lastpoi.set(poimove.x, poimove.y); } } else if (mTouchMovePoints.size() == 2) {// 2个触点在动 // 2个点可能是平移或者缩放或者旋转 Point poimove0 = mTouchMovePoints.valueAt(0); Point poimove1 = mTouchMovePoints.valueAt(1); Point lastPoi0 = mTouchPoints.get(poimove0.id); Point lastPoi1 = mTouchPoints.get(poimove1.id); // 移动指向向量 Point x0 = new Point(poimove0.x - lastPoi0.x, poimove0.y - lastPoi0.y, poimove0.id); Point x1 = new Point(poimove1.x - lastPoi1.x, poimove1.y - lastPoi1.y, poimove1.id); double diffm = Math.sqrt((Math.pow(x0.x, 2) + Math.pow(x0.y, 2))); double linem = Math.sqrt((Math.pow(x1.x, 2) + Math.pow(x1.y, 2))); double cos = (x0.x * x1.x + x0.y * x1.y) / (diffm * linem); if (cos > 0) {// 夹角小于90度为平移 Point anchor = getCenterPoint(poimove0, poimove1); int dt = anchor.x - (int) ((lastPoi0.x + lastPoi1.x) * 1.0 / 2 + 0.5); mGesturesL.OnChange(anchor, Gestures.translation, dt, v, event); lastPoi0.set(poimove0.x, poimove0.y); lastPoi1.set(poimove1.x, poimove1.y); } else {// 钝角即为缩放 // double r = (diffm-linem)/(diffm+linem); // 设置锚点 double d0 = Math .sqrt((Math.pow(lastPoi0.x - lastPoi1.x, 2) + Math.pow(lastPoi0.y - lastPoi1.y, 2))); double d1 = Math .sqrt((Math.pow(poimove0.x - poimove1.x, 2) + Math.pow(poimove0.y - poimove1.y, 2))); // double d = d1/d0>1?1.2:0.8; double scale = 1; if (d0 != 0) scale = d1 / d0; mGesturesL.OnChange(getCenterPoint(poimove0, poimove1), Gestures.scale, scale, v, event); lastPoi0.set(poimove0.x, poimove0.y); lastPoi1.set(poimove1.x, poimove1.y); } } break; case MotionEvent.ACTION_UP: clearPoint(); mGesturesL.OnChange(null, Gestures.up, 0, v, event); break; case MotionEventCompat.ACTION_POINTER_DOWN: v.getParent().requestDisallowInterceptTouchEvent(true); initPoint(event); break; case MotionEventCompat.ACTION_POINTER_UP: initPoint(event); break; } } catch (Exception e) { // e.printStackTrace(); } return true; } private boolean mIntercept; public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getPointerCount() > 1) mIntercept = true; switch (getAction(ev)) { case MotionEvent.ACTION_DOWN: mIntercept = false; break; case MotionEventCompat.ACTION_POINTER_DOWN: mIntercept = true; break; } return mIntercept; } private Point getCenterPoint(Point p0, Point p1) { Point point = new Point(); point.set((int) ((p0.x + p1.x) * 1.0 / 2 + 0.5), (int) ((p0.y + p1.y) * 1.0 / 2 + 0.5)); return point; } private Point getOtherPoint(Point lastpoi) { Point otherPoi = null; for (int i = 0; i < mTouchPoints.size(); i++) { otherPoi = mTouchPoints.valueAt(i); if (!otherPoi.equals(lastpoi)) break; } return otherPoi.id!=lastpoi.id?otherPoi:null; } private void clearPoint() { mTouchPoints.clear(); // mTouchMovePoints.clear(); } private int getOffset(Point P, MotionEvent event, int index) { int xDiff = Math.abs(P.x - (int) (MotionEventCompat.getX(event, index) + 0.5f)); int yDiff = Math.abs(P.y - (int) (MotionEventCompat.getY(event, index) + 0.5f)); return (int) (Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) + 0.5f); } /** * 移除被释放的触点 * * @param event */ private void initPoint(MotionEvent event) { clearPoint(); for (int i = 0; i < event.getPointerCount(); i++) { int pointerId = event.getPointerId(i); Point point = getPoint(event, i); mTouchPoints.put(pointerId, point); // mTouchMovePoints.put(pointerId, point); } } private void putPoint(int id, Point p) { mTouchPoints.put(id, p); // mTouchMovePoints.put(id, p); } private Point getPoint(MotionEvent event, int index) { return new Point(getX(event, index), getY(event, index), event.getPointerId(index)); } private int getX(MotionEvent event, int i) { return (int) (event.getX(i) + 0.5f); } private int getY(MotionEvent event, int i) { return (int) (event.getY(i) + 0.5f); } private int getAction(MotionEvent event) { return event.getAction() & MotionEventCompat.ACTION_MASK; } private int getTouchSlop(Context c) { return ViewConfigurationCompat.getScaledPagingTouchSlop(ViewConfiguration.get(c)); } /** * 手势:缩放,平移(手势平移要求至少2个手指拖动),旋转 */ public static enum Gestures { up,scale, translation; } // public static enum scale{ // // } // public static enum rotate{ // // 4000 } // public static enum translation{ // // } private static class GesturesL implements OnGesturesChangeListener { private OnGesturesChangeListener l; private boolean mGesturesRunning; public void OnChange(Point anchor, Gestures gestures, double d, View v, MotionEvent event) { if(gestures!=Gestures.up){ mGesturesRunning = true; if (l != null) l.OnChange(anchor, gestures, d, v, event); }else if (mGesturesRunning) { if (l != null) l.OnChange(anchor, gestures, d, v, event); mGesturesRunning = false; } // Log.i("info", gestures.name() + " " + d); } } public MultiTouchGestures setOnGesturesChangeListener(OnGesturesChangeListener l) { mGesturesL.l = l; return this; } public static interface OnGesturesChangeListener { /** * @param anchor * 锚点,推荐不动点 * @param gestures * 手势 * @param progress * 手势动作进度<br> * {@link MultiTouchGestures.Gestures#scale} * 缩放,手势发生时与上一次缩放前的比例<br> * {@link MultiTouchGestures.Gestures#translation} 平移<br> */ void OnChange(Point anchor, Gestures gestures, double progress, View v, MotionEvent event); } public static class Point { public int id; public int x; public int y; public Point() { } public Point(int x, int y, int id) { this.id = id; this.x = x; this.y = y; } public void set(int x, int y) { this.x = x; this.y = y; } @Override public String toString() { return "Point [id=" + id + ", x=" + x + ", y=" + y + "]"; } } }
相关文章推荐
- Android 手势检测实战 打造支持缩放平移的图片预览效果(上)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(上)
- 转:Android 手势检测实战 打造支持缩放平移的图片预览效果
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(上)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(上)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(上)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(上)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(上)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
- Android 图片随着手势缩放,平移,并且支持多点触控
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(上)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(上)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)