android:ViewPager和Horizo​​ntalScrollVIew

我的ViewPager有一个HorizontalScrollView 。 我设置了requestDisallowInterceptTouchEvent(true); 对于HorizontalScrollViewViewPager仍然有时会拦截触摸事件。 是否有另一个命令,我可以用来防止视图的父母和祖先拦截触摸事件?

注意: HorizontalScrollView只占用一半的屏幕。

我有同样的问题。 我的解决scheme是:

  1. ViewPager的子类并添加一个名为ViewPager的属性。
  2. childId属性创build一个setter,并设置HorizontalScrollView的id。
  3. 重写onInterceptTouchEvent()的子类中的onInterceptTouchEvent() ,如果ViewPager属性大于0,则获取该子项,并且如果HorizontalScrollView区域中的事件返回false。

 public class CustomViewPager extends ViewPager { private int childId; public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (childId > 0) { View scroll = findViewById(childId); if (scroll != null) { Rect rect = new Rect(); scroll.getHitRect(rect); if (rect.contains((int) event.getX(), (int) event.getY())) { return false; } } } return super.onInterceptTouchEvent(event); } public void setChildId(int id) { this.childId = id; } } 

onCreate()方法中

 viewPager.setChildId(R.id.horizontalScrollViewId); adapter = new ViewPagerAdapter(this); viewPager.setAdapter(adapter); 

希望这个帮助

谢谢回复。 我修改了一下你的解决scheme,并设法使嵌套的ViewPagers工作:

 public class CustomViewPager extends ViewPager { private int childId; public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (childId > 0) { ViewPager pager = (ViewPager)findViewById(childId); if (pager != null) { pager.requestDisallowInterceptTouchEvent(true); } } return super.onInterceptTouchEvent(event); } public void setChildId(int id) { this.childId = id; } } 

所以,我知道这个问题已经很老了,但是我已经提出了一个解决scheme,我认为这个解决scheme比在这里发布的解决scheme有一些额外的优势。 可能发生的一种情况是,我可以在ViewPager中有多个Horizo​​ntalScrollView(我这样做),然后我需要向ViewPager提供大量的Ids,以便始终检查是否存在子触摸冲突。

我分析了ViewPager的源代码,发现它们使用了这个名为“canScroll”的方法来确定子视图是否可以滚动。 幸运的是,它不是静态的也不是最终的,所以我可以重写它。 在该方法中,调用了“布尔ViewCompat.canScrollHorizo​​ntally(View,int)”(对于SDK <14总是返回false)。 我的解决scheme是:

 public class CustomViewPager extends ViewPager { public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } public CustomViewPager(Context context) { super(context); } protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { return super.canScroll(v, checkV, dx, x, y) || (checkV && customCanScroll(v)); } protected boolean customCanScroll(View v) { if (v instanceof HorizontalScrollView) { View hsvChild = ((HorizontalScrollView) v).getChildAt(0); if (hsvChild.getWidth() > v.getWidth()) return true; } return false; } } 

所以,如果你在ViewPager中有一个不同的View类,它也应该能够接收到水平拖动,只需要改变customCanScroll(View),这样你就可以返回,如果不能拦截的话。

如果当前视图也应该检查“可滚动性”,则布尔checkV为true,这就是为什么我们也应该检查这一点。

希望这有助于解决未来这样的问题(或者如果有更好的解决scheme,或者来自Android平台的官方解决scheme,请告诉我)。

我不知道你是否已经解决了这个问题。 但上面的答案都没有正常工作。 所以我认为对那些可能正在寻找解决scheme的人来说是必要的。

事实上,如果您阅读有关在ViewGroup中处理触摸事件的官方文档,解决scheme非常简单。

首先你需要了解的用法

ViewParent.requestDisallowInterceptTouchEvent(boolean) ,在父View上调用它来表明它不应该用onInterceptTouchEvent(MotionEvent)拦截触摸事件。

然后,您需要拦截事件并确保您的Horizo​​ntalScrollView的父ViewGroup不会再发送事件。

所以,为你设置一个OnToushListener Horizo​​ntalScrollView。 检测触摸并移动事件,然后将requestDisallowInterceptTouchEvent(true)设置为其父项(ViewPager或sth else),以确保事件由Horizo​​ntalScrollView处理。

当然,你可以把下面的代码放到你的CustomHorizo​​ntalScrollView组件中,这样它就可以被重用了。

希望它有帮助。 😉

 horizontalScrollView.setOnTouchListener(new View.OnTouchListener() { float rawX; int mTouchSlop = ViewConfiguration.get(getActivity()).getScaledTouchSlop(); @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: v.getParent().requestDisallowInterceptTouchEvent(true); rawX = event.getRawX(); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: v.getParent().requestDisallowInterceptTouchEvent(false); rawX = 0f; break; case MotionEvent.ACTION_MOVE: if (Math.abs(rawX - event.getRawX()) > mTouchSlop) v.getParent().requestDisallowInterceptTouchEvent(true); break; } return false; } 

这是另一个为我工作的解决scheme,

创build一个自定义的ViewPager

 public class NoScrollViewPager extends ViewPager { private boolean scrollDisable = false; public NoScrollViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if(scrollDisable) { return false; } else { return super.onInterceptTouchEvent(ev); } } public void disableScroll() { scrollDisable = true; } public void enableScroll() { scrollDisable = false; } } 

然后将OnTouchListener添加到您的项目,无论是Horizo​​ntalScrollView还是其他任何您不希望viewpager在触摸时滚动的项目。

 gf.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View arg0, MotionEvent ev) { switch(ev.getAction()) { case MotionEvent.ACTION_DOWN: viewPager.disableScroll(); break; case MotionEvent.ACTION_UP: viewPager.enableScroll(); break; } return false; } }); 

费德的解决scheme对我来说效果不佳。 我的Horizo​​ntalScrollVIew有它没有捕获任何input(点击,滑动..)的区域。 我想getHitRect()必须做些什么。 用下面的代码replace它后,一切正常。

可以添加多个Horizo​​ntalScrollVIew视图或任何其他需要关注的视图。

 public class CustomViewPager extends ViewPager { private ArrayList<Integer> children; public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); children = new ArrayList<Integer>(); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (children.size() > 0) { for(int i=0; i<children.size(); i++){ View scroll = findViewById(children.get(i)); if (scroll != null & scroll.isPressed()) { return false; } } } return super.onInterceptTouchEvent(event); } public void addChildId(int id) { children.add(id); } } 

在XML中你将会有这样的东西:

 <form.paginator.lib.CustomViewPager android:id="@+id/pager" android:layout_width="fill_parent" android:layout_height="150dp" /> 

在onCreate()方法中:

 mPager = (CustomViewPager) findViewById(R.id.pager); mPager.setAdapter(mAdapter); mPager.addChildId(R.id.avatarImageView); 

在视图的OnTouchListener()方法中,您已添加到CustomViewPager子项中:

 case MotionEvent.ACTION_DOWN: v.setPressed(true); . . . case MotionEvent.ACTION_UP: v.setPressed(false); 

我在viewpager组的第一页脚下有一个小画廊的风景。 在滑animation廊视图焦点会跳转之间移animation廊项目或viewpager。

重写上面列出的ViewPager并设置requestDisallowInterceptTouchEvent解决了我的问题。 滑动galleryview时页面不再改变。 对于那些使用viewpager使用galleryview的人来说,这是一个重要的解决scheme。

这也适用于scrollview内的viewpager: https ://stackoverflow.com/a/2655740/969325

我发现,如果你在ScrollView中有一个ViewPager,并且你希望它始终保持焦点,那么当你触摸它并且ScrollView永远不会得到焦点的时候,就会这样做。

  mViewPager= (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(adapter); mViewPager.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { mViewPager.getParent().requestDisallowInterceptTouchEvent(true); return false; } }); 

经过testing了很多解决scheme,我find了这个。 在MyPagerView中:

 @Override public boolean onTouchEvent(MotionEvent event) { if (childId > 0) { View scroll = findViewById(childId); if (scroll != null && mGestureDetector.onTouchEvent(event)) { return false; } } return super.onTouchEvent(event); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (childId > 0) { HorizontalScrollView scroll = (HorizontalScrollView)findViewById(childId); if (scroll != null && mGestureDetector.onTouchEvent(event)) { return false; } } return super.onInterceptTouchEvent(event); } 

所以,我修改了Fede的答案,因为它禁用了我想要的页面中同一区域的触摸。 此外,我使它能够添加多个视图,因为我正在处理大量使用横向拖放交互的graphics和交互视图。 这样你可以添加

 public class CustomViewPager extends ViewPager { private List<ViewFocus> lateralTouchViews = new ArrayList<>(); public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { for(int i = 0; i< lateralTouchViews.size(); i++){ View scroll = findViewById(lateralTouchViews.get(i).id); if (scroll != null && getCurrentItem() == lateralTouchViews.get(i).itemPosition) { Rect rect = new Rect(); scroll.getHitRect(rect); if (rect.contains((int) event.getX(), (int) event.getY())) { return false; } } } return super.onInterceptTouchEvent(event); } public void addConflict(int id, int pageIndex) { lateralTouchViews.add(new ViewFocus(id, pageIndex)); } public class ViewFocus{ int id; int itemPosition; public ViewFocus(int id, int itemPosition){ this.id = id; this.itemPosition = itemPosition; } } 

}