滑动和正常滚动有问题
Trouble with swiping and normal scrolling
我的 activity 包含一个 TextView 设置在一个覆盖整个屏幕的 ScrollView 中。 TextView 中的内容通常是多页的长度。
我正在尝试启用触摸控件,包括单击、双击、向左滑动、向右滑动和捏合,这些都工作正常。
然而,问题是用户很难通过不小心向上或向下滚动 ScrollView(从而取消滑动检测)向左或向右滑动
这是我在 TextView 上使用的自定义 OnTouchListener
public class OnSwipeTouchListener implements OnTouchListener {
private final GestureDetector gestureDetector;
private boolean mTapConsumed = false;
private int mTapsDetected = 0;
private boolean mEnableTap = true;
public OnSwipeTouchListener (Context ctx){
gestureDetector = new GestureDetector(ctx, new GestureListener());
}
private double mPinchOriginalDistance = 0;
private float mPinchLastScale = 1.0f; //scale change for current pinch action
private ScrollView mScrollView;
@Override
public boolean onTouch(View v, MotionEvent event) {
mScrollView = (ScrollView) v.getParent();
if(event.getPointerCount() == 2) {
mScrollView.requestDisallowInterceptTouchEvent(true);
mTapConsumed = true;
mTapsDetected = 0;
switch(event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_POINTER_DOWN:
//pinch mode
float distx, disty;
//Get the current distance
distx = event.getX(0) - event.getX(1);
disty = event.getY(0) - event.getY(1);
mPinchOriginalDistance = Math.sqrt(distx * distx + disty * disty);
break;
case MotionEvent.ACTION_MOVE:
//Get the current distance
distx = event.getX(0) - event.getX(1);
disty = event.getY(0) - event.getY(1);
double distance = Math.sqrt(distx * distx + disty * disty);
if(mPinchOriginalDistance == 0)
break;
float scale = (float)(distance / mPinchOriginalDistance);
mPinchLastScale = scale;
onPinchScaleChange(scale);
break;
case MotionEvent.ACTION_POINTER_UP:
onPinchFinal(mPinchLastScale);
mPinchOriginalDistance = 0;
mPinchLastScale = 1.0f;
break;
default:
break;
}
return true;
}
else
return gestureDetector.onTouchEvent(event);
}
private final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 80;
private static final int SWIPE_VELOCITY_THRESHOLD = 60;
private final static int GESTURE_TAP_DELAY = 300;
private final static int GESTURE_FLING_DELAY = 1000;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
if(!mEnableTap)
return true;
mTapConsumed = false;
mTapsDetected++;
if(mTapsDetected == 1)
handler.postDelayed(checkTap, GESTURE_TAP_DELAY);
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if(!mEnableTap)
return true;
mTapConsumed = false;
mTapsDetected++;
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
mEnableTap = false;
mTapConsumed = true;
mTapsDetected = 0;
handler.removeCallbacks(postFling);
handler.postDelayed(postFling, GESTURE_FLING_DELAY); //dont allow a tap to be registered for a certain time
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
flingData(diffX, diffY);
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
result = true;
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
//Prevents a single tap being detected as well as a double tap
private Handler handler = new Handler();
private Runnable checkTap = new Runnable() {
public void run() {
try {
if(!mTapConsumed && mTapsDetected >= 1) {
if(mTapsDetected > 1)
onTapDouble();
else
onTapSingle();
mTapsDetected = 0;
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
};
//Prevents a tap from being detected for a short duration after a fling has occurred
private Runnable postFling = new Runnable() {
public void run() {
try {
mEnableTap = true;
}
catch(Exception e)
{
e.printStackTrace();
}
}
};
public void onSwipeRight() {
}
public void onSwipeLeft() {
}
public void onPinchScaleChange(float scale) {
}
public void onPinchFinal(float scale) {
}
public void onTapSingle() {
}
public void onTapDouble() {
}
public void flingData(float diffX, float diffY)
{
}
}
说清楚。
上面的代码有效,但用户很难激活向左或向右滑动,因为 ScrollView 想要向上或向下滚动。
我需要一种方法让用户更容易左右滑动。
有什么想法吗?
事实证明,有时最简单的答案是最好的。
我将 onTouchListener 应用于滚动视图而不是文本视图,世界上一切都很好。 :)
我的 activity 包含一个 TextView 设置在一个覆盖整个屏幕的 ScrollView 中。 TextView 中的内容通常是多页的长度。
我正在尝试启用触摸控件,包括单击、双击、向左滑动、向右滑动和捏合,这些都工作正常。 然而,问题是用户很难通过不小心向上或向下滚动 ScrollView(从而取消滑动检测)向左或向右滑动
这是我在 TextView 上使用的自定义 OnTouchListener
public class OnSwipeTouchListener implements OnTouchListener {
private final GestureDetector gestureDetector;
private boolean mTapConsumed = false;
private int mTapsDetected = 0;
private boolean mEnableTap = true;
public OnSwipeTouchListener (Context ctx){
gestureDetector = new GestureDetector(ctx, new GestureListener());
}
private double mPinchOriginalDistance = 0;
private float mPinchLastScale = 1.0f; //scale change for current pinch action
private ScrollView mScrollView;
@Override
public boolean onTouch(View v, MotionEvent event) {
mScrollView = (ScrollView) v.getParent();
if(event.getPointerCount() == 2) {
mScrollView.requestDisallowInterceptTouchEvent(true);
mTapConsumed = true;
mTapsDetected = 0;
switch(event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_POINTER_DOWN:
//pinch mode
float distx, disty;
//Get the current distance
distx = event.getX(0) - event.getX(1);
disty = event.getY(0) - event.getY(1);
mPinchOriginalDistance = Math.sqrt(distx * distx + disty * disty);
break;
case MotionEvent.ACTION_MOVE:
//Get the current distance
distx = event.getX(0) - event.getX(1);
disty = event.getY(0) - event.getY(1);
double distance = Math.sqrt(distx * distx + disty * disty);
if(mPinchOriginalDistance == 0)
break;
float scale = (float)(distance / mPinchOriginalDistance);
mPinchLastScale = scale;
onPinchScaleChange(scale);
break;
case MotionEvent.ACTION_POINTER_UP:
onPinchFinal(mPinchLastScale);
mPinchOriginalDistance = 0;
mPinchLastScale = 1.0f;
break;
default:
break;
}
return true;
}
else
return gestureDetector.onTouchEvent(event);
}
private final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 80;
private static final int SWIPE_VELOCITY_THRESHOLD = 60;
private final static int GESTURE_TAP_DELAY = 300;
private final static int GESTURE_FLING_DELAY = 1000;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
if(!mEnableTap)
return true;
mTapConsumed = false;
mTapsDetected++;
if(mTapsDetected == 1)
handler.postDelayed(checkTap, GESTURE_TAP_DELAY);
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if(!mEnableTap)
return true;
mTapConsumed = false;
mTapsDetected++;
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
mEnableTap = false;
mTapConsumed = true;
mTapsDetected = 0;
handler.removeCallbacks(postFling);
handler.postDelayed(postFling, GESTURE_FLING_DELAY); //dont allow a tap to be registered for a certain time
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
flingData(diffX, diffY);
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
result = true;
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
//Prevents a single tap being detected as well as a double tap
private Handler handler = new Handler();
private Runnable checkTap = new Runnable() {
public void run() {
try {
if(!mTapConsumed && mTapsDetected >= 1) {
if(mTapsDetected > 1)
onTapDouble();
else
onTapSingle();
mTapsDetected = 0;
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
};
//Prevents a tap from being detected for a short duration after a fling has occurred
private Runnable postFling = new Runnable() {
public void run() {
try {
mEnableTap = true;
}
catch(Exception e)
{
e.printStackTrace();
}
}
};
public void onSwipeRight() {
}
public void onSwipeLeft() {
}
public void onPinchScaleChange(float scale) {
}
public void onPinchFinal(float scale) {
}
public void onTapSingle() {
}
public void onTapDouble() {
}
public void flingData(float diffX, float diffY)
{
}
}
说清楚。 上面的代码有效,但用户很难激活向左或向右滑动,因为 ScrollView 想要向上或向下滚动。 我需要一种方法让用户更容易左右滑动。 有什么想法吗?
事实证明,有时最简单的答案是最好的。 我将 onTouchListener 应用于滚动视图而不是文本视图,世界上一切都很好。 :)