ScrollView 触摸处理中的 Horizo​​ntalScrollView

本教程将介绍ScrollView 触摸处理中的 Horizo​​ntalScrollView的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

ScrollView 触摸处理中的 Horizo​​ntalScrollView 教程 第1张

问题描述

我有一个 ScrollView 围绕我的整个布局,以便整个屏幕都可以滚动.我在这个 ScrollView 中的第一个元素是一个 Horizo​​ntalScrollView 块,它具有可以水平滚动的功能.我在水平滚动视图中添加了一个 ontouchlistener 来处理触摸事件并强制视图捕捉"到 ACTION_UP 事件上最近的图像.

所以我想要的效果就像普通的 android 主屏幕,您可以在其中从一个滚动到另一个,当您抬起手指时它会捕捉到一个屏幕.

这一切都很好,除了一个问题:我需要从左到右几乎完美地水平滑动才能注册 ACTION_UP.如果我至少垂直滑动(我认为很多人在左右滑动时倾向于在手机上这样做),我将收到 ACTION_CANCEL 而不是 ACTION_UP.我的理论是这是因为水平滚动视图在滚动视图中,滚动视图劫持垂直触摸以允许垂直滚动.

怎么在水平滚动视图中禁用滚动视图的触摸事件,但仍允许在滚动视图的其他位置正常垂直滚动?

这是我的代码示例:

public class HomeFeatureLayout extends HorizontalScrollView {
 private ArrayList<ListItem> items = null;
 private GestureDetector gestureDetector;
 View.OnTouchListener gestureListener;
 private static final int SWIPE_MIN_DISTANCE = 5;
 private static final int SWIPE_THRESHOLD_VELOCITY = 300;
 private int activeFeature = 0;

 public HomeFeatureLayout(Context context, ArrayList<ListItem> items){
  super(context);
  setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
  setFadingEdgeLength(0);
  this.setHorizontalScrollBarEnabled(false);
  this.setVerticalScrollBarEnabled(false);
  LinearLayout internalWrapper = new LinearLayout(context);
  internalWrapper.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
  internalWrapper.setOrientation(LinearLayout.HORIZONTAL);
  addView(internalWrapper);
  this.items = items;
  for(int i = 0; i< items.size();i++){
LinearLayout featureLayout = (LinearLayout) View.inflate(this.getContext(),R.layout.homefeature,null);
TextView header = (TextView) featureLayout.findViewById(R.id.featureheader);
ImageView image = (ImageView) featureLayout.findViewById(R.id.featureimage);
TextView title = (TextView) featureLayout.findViewById(R.id.featuretitle);
title.setTag(items.get(i).GetLinkURL());
TextView date = (TextView) featureLayout.findViewById(R.id.featuredate);
header.setText("FEATURED");
Image cachedImage = new Image(this.getContext(), items.get(i).GetImageURL());
image.setImageDrawable(cachedImage.getImage());
title.setText(items.get(i).GetTitle());
date.setText(items.get(i).GetDate());
internalWrapper.addView(featureLayout);
  }
  gestureDetector = new GestureDetector(new MyGestureDetector());
  setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
 if (gestureDetector.onTouchEvent(event)) {
  return true;
 }
 else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL ){
  int scrollX = getScrollX();
  int featureWidth = getMeasuredWidth();
  activeFeature = ((scrollX + (featureWidth/2))/featureWidth);
  int scrollTo = activeFeature*featureWidth;
  smoothScrollTo(scrollTo, 0);
  return true;
 }
 else{
  return false;
 }
}
  });
 }

 class MyGestureDetector extends SimpleOnGestureListener {
  @Override
  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
 //right to left 
 if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
  activeFeature = (activeFeature < (items.size() - 1))? activeFeature + 1:items.size() -1;
  smoothScrollTo(activeFeature*getMeasuredWidth(), 0);
  return true;
 } //left to right
 else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
  activeFeature = (activeFeature > 0)? activeFeature - 1:0;
  smoothScrollTo(activeFeature*getMeasuredWidth(), 0);
  return true;
 }
} catch (Exception e) {
 // nothing
}
return false;
  }
 }
}

推荐答案

更新:我想通了.在我的 ScrollView 上,我需要重写 onInterceptTouchEvent 方法以仅在 Y 运动大于 X 运动时拦截触摸事件.似乎 ScrollView 的默认行为是在有任何 Y 运动时拦截触摸事件.因此,通过修复,ScrollView 只会在用户故意在 Y 方向滚动时拦截事件,并且在这种情况下将 ACTION_CANCEL 传递给子级.

这是包含 Horizo​​ntalScrollView 的 Scroll View 类的代码:

public class CustomScrollView extends ScrollView {
 private GestureDetector mGestureDetector;

 public CustomScrollView(Context context, AttributeSet attrs) {
  super(context, attrs);
  mGestureDetector = new GestureDetector(context, new YScrollDetector());
  setFadingEdgeLength(0);
 }

 @Override
 public boolean onInterceptTouchEvent(MotionEvent ev) {
  return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
 }

 // Return false if we're scrolling in the x direction class YScrollDetector extends SimpleOnGestureListener {
  @Override
  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 
return Math.abs(distanceY) > Math.abs(distanceX);
  }
 }
}

好了关于ScrollView 触摸处理中的 Horizo​​ntalScrollView的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。