Android conflict between, OnTouchListener SimpleOnGestureListener and setOnClickListener
我正在尝试创建动画:
用例:
1. 用户向右(水平)滑动/拖动项目,项目被添加到购物篮中。如果他再次刷卡,它会在篮子中再添加一件相同的物品。
2. 用户向左(水平)滑动/拖动项目,项目从购物篮中移除,如果之前添加,如果购物篮中没有项目,我们保持原样。
拖动效果:当用户拖动时,项目会随着手指一起移动。他一离开,物品就会回到原来的位置。
缩放效果:当用户点击商品时,商品会被放大,让用户知道商品已添加到购物篮中。 (复制右键拖拽的方法)。
我尝试专门为此目的使用 OnSwipeTouchListener 类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | import android.content.Context; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import PointF; public class OnSwipeTouchListener implements OnTouchListener { private final GestureDetector gestureDetector; PointF DownPT = null; PointF StartPT = null; float startX; float startY; public OnSwipeTouchListener(Context context , float x, float y) { gestureDetector = new GestureDetector(context, new GestureListener()); DownPT = new PointF(); StartPT = new PointF(); this.startX = x; this.startY = y; } public void onSwipeLeft() { } public void onSwipeRight() { } public boolean onTouch(View v, MotionEvent event) { int eid = event.getAction(); switch (eid) { case MotionEvent.ACTION_MOVE: PointF mv = new PointF(event.getX() - DownPT.x, event.getY() - DownPT.y); v.setX((int) (StartPT.x + mv.x)); v.setY(this.startY); StartPT = new PointF(v.getX(), v.getY()); break; case MotionEvent.ACTION_DOWN: DownPT.x = event.getX(); DownPT.y = event.getY(); StartPT = new PointF(v.getX(), v.getY()); break; case MotionEvent.ACTION_UP: // Move image back to its original position. v.setX(this.startX); v.setY(this.startY); break; default: v.setX(this.startX); v.setY(this.startY); break; } return gestureDetector.onTouchEvent(event); } private final class GestureListener extends SimpleOnGestureListener { private static final int SWIPE_DISTANCE_THRESHOLD = 100; private static final int SWIPE_VELOCITY_THRESHOLD = 100; @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { float distanceX = e2.getX() - e1.getX(); float distanceY = e2.getY() - e1.getY(); if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { if (distanceX > 0) onSwipeRight(); else onSwipeLeft(); return true; } return false; } } } |
当我的方法 OnTouch 如下所示时,我的 onSwipeRight() 和 onSwipeLeft() 被触发,但是当我在代码中实现了上面的 onTouch 时,这两个方法不会被触发。
1 2 3 |
关于点击事件的缩放效果。
在我的 Fragment 中,我正在像这样缩放图像。
offerimg1.setOnClickListener(new View.OnClickListener() {
1 2 3 4 5 6 | @Override public void onClick(View v) { // TODO Auto-generated method stub zoomAnimation(v, offerimg1); } }); |
而我的 zoomAnimation 方法是:
1 2 3 4 | private void zoomAnimation(View view,ImageView image) { Animation animation = AnimationUtils.loadAnimation(getActivity().getApplicationContext(), R.anim.zoom); image.startAnimation(animation); } |
除非我没有在我的碎片中实现,否则我的 Zoom 正在工作:
1 2 3 4 5 6 7 8 9 10 11 12 | offerimg1.setOnTouchListener(new OnSwipeTouchListener(getActivity().getApplicationContext(),offerimg1.getX(),offerimg1.getY()) { @Override public void onSwipeLeft() { Log.d("onTouch"," swipe left"); } @Override public void onSwipeRight() { Log.d("onTouch"," swipe right"); } }); |
我不确定这些事件之间的冲突是什么。我需要实现我上面的用例,每个事件都应该在每个图像上工作。由于我的图像在片段中的滚动视图中。
如果你愿意,我可以在这里分享更多代码。如果我无法澄清我的问题,请告诉我。
非常感谢您的帮助。
问候,
沙香克·普拉塔普
终于把问题解决了,
发现上述代码有问题:
onSwipeLeft() and onSwipeRight().. since my image is moving along with
my finger, this is the reason distanceX is turing out to be zero,
which is always less than static SWIPE_DISTANCE_THRESHOLD. and in the
code we are saying that if distanceX is negative its swipeLeft() else
swipeRight()
解决方案:
我们需要某种方式来捕捉用户移动手指的方式,因此我决定在 MotionEvent.ACTION_MOVE: 事件中,找出 mv.x 是负数还是 mv.x 是正数。一旦我找到它,就很容易做出决定,在此基础上我们可以决定在 GestureListener.
中运行哪个方法
这是我的 OnSwipeTouchListener,我仍然不确定这是否是这种情况的最佳解决方案,但我发现它适用于 AVD 和 Android 设备。
我仍然愿意找到一种很好且清晰的方法(最佳实践)来执行此操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | import android.content.Context; import android.content.res.Resources; import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewConfiguration; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.ImageView; import android.widget.Toast; import R; import StartingPoints; import PointF; public class OnSwipeTouchListener implements OnTouchListener { private static final String APP = OnSwipeTouchListener.class.getName() ; private final GestureDetector gestureDetector; PointF DownPT = null; PointF StartPT = null; Context _context; static boolean isLeftMoved = false; static boolean isRightMoved = false; /** * Max allowed duration for a"click", in milliseconds. */ private static final int MAX_CLICK_DURATION = 1000; /** * Max allowed distance to move during a"click", in DP. */ private static final int MAX_CLICK_DISTANCE = 15; private static final float PIXELS_PER_SECOND = 5; private long pressStartTime; private float pressedX; private float pressedY; private boolean stayedWithinClickDistance; Resources resources; private float startX = 0f; private float startY = 0f; private boolean isNewImage = true; public OnSwipeTouchListener(Context context, Resources resources) { this._context = context; gestureDetector = new GestureDetector(context, new GestureListener()); DownPT = new PointF(); StartPT = new PointF(); this.resources = resources; } public void onSwipeLeft() { } public void onSwipeRight() { } public boolean onTouch(View v, MotionEvent e) { if(isNewImage){ isNewImage = false; startX = v.getX(); startY = v.getY(); } switch (e.getAction()) { case MotionEvent.ACTION_DOWN: //animation code DownPT.x = e.getX(); DownPT.y = e.getY(); StartPT = new PointF(v.getX(), v.getY()); //calculation code pressStartTime = System.currentTimeMillis(); pressedX = e.getX(); pressedY = e.getY(); stayedWithinClickDistance = true; break; case MotionEvent.ACTION_MOVE: // animation code PointF mv = new PointF(e.getX() - DownPT.x, e.getY() - DownPT.y); v.setX((int) (StartPT.x + mv.x)); v.setY(startY); StartPT = new PointF(v.getX(), v.getY()); if(mv.x < 0 ){ isLeftMoved = true; } if(mv.x > 0 ){ isRightMoved = true; } //calculation code if (stayedWithinClickDistance && distance(pressedX, pressedY, e.getX(), e.getY()) > MAX_CLICK_DISTANCE) { stayedWithinClickDistance = false; } Log.d("Moved","Item moved"); break; case MotionEvent.ACTION_UP: if(!stayedWithinClickDistance){ v.setX(startX); v.setY(startY); isNewImage = true; } long pressDuration = System.currentTimeMillis() - pressStartTime; if (pressDuration < MAX_CLICK_DURATION && stayedWithinClickDistance) { // Click event has occurred Log.d("Stayed"," With Click event"); zoomAnimation(v); isNewImage = true; } break; default: // Move image back to its original position, by default Log.d("default","This is default"); v.setX(startX); v.setY(startY); isNewImage = true; break; } return gestureDetector.onTouchEvent(e); } private float distance(float x1, float y1, float x2, float y2) { float dx = x1 - x2; float dy = y1 - y2; float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy); return pxToDp(distanceInPx); } private float pxToDp(float px) { return px / resources.getDisplayMetrics().density; } private void zoomAnimation(View view) { Animation animation = AnimationUtils.loadAnimation(_context, R.anim.zoom); view.startAnimation(animation); } private final class GestureListener extends SimpleOnGestureListener { private static final int SWIPE_DISTANCE_THRESHOLD = 20; private static final int SWIPE_VELOCITY_THRESHOLD = 50; @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { float maxFlingVelocity = ViewConfiguration.get(_context).getScaledMaximumFlingVelocity(); float velocityPercentX = velocityX / maxFlingVelocity; // the percent is a value in the range of (0, 1] float normalizedVelocityX = velocityPercentX * PIXELS_PER_SECOND; // where PIXELS_PER_SECOND is a device-independent measurement float distanceX = e2.getX() - e1.getX(); float distanceY = e2.getY() - e1.getY(); if (isLeftMoved || isRightMoved) { if(isRightMoved) { isLeftMoved = false; isRightMoved = false; onSwipeRight(); } else { isLeftMoved = false; isRightMoved = false; onSwipeLeft(); } } return false; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { return true; } } } |
最好的问候,
沙香克·普拉塔普