android:ViewPager和HorizontalScrollVIew
我的ViewPager
有一个HorizontalScrollView
。 我设置了requestDisallowInterceptTouchEvent(true);
对于HorizontalScrollView
但ViewPager
仍然有时会拦截触摸事件。 是否有另一个命令,我可以用来防止视图的父母和祖先拦截触摸事件?
注意: HorizontalScrollView
只占用一半的屏幕。
我有同样的问题。 我的解决scheme是:
-
ViewPager
的子类并添加一个名为ViewPager
的属性。 - 为
childId
属性创build一个setter,并设置HorizontalScrollView
的id。 - 重写
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中有多个HorizontalScrollView(我这样做),然后我需要向ViewPager提供大量的Ids,以便始终检查是否存在子触摸冲突。
我分析了ViewPager的源代码,发现它们使用了这个名为“canScroll”的方法来确定子视图是否可以滚动。 幸运的是,它不是静态的也不是最终的,所以我可以重写它。 在该方法中,调用了“布尔ViewCompat.canScrollHorizontally(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)拦截触摸事件。
然后,您需要拦截事件并确保您的HorizontalScrollView的父ViewGroup不会再发送事件。
所以,为你设置一个OnToushListener HorizontalScrollView。 检测触摸并移动事件,然后将requestDisallowInterceptTouchEvent(true)设置为其父项(ViewPager或sth else),以确保事件由HorizontalScrollView处理。
当然,你可以把下面的代码放到你的CustomHorizontalScrollView组件中,这样它就可以被重用了。
希望它有帮助。 😉
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添加到您的项目,无论是HorizontalScrollView还是其他任何您不希望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对我来说效果不佳。 我的HorizontalScrollVIew有它没有捕获任何input(点击,滑动..)的区域。 我想getHitRect()必须做些什么。 用下面的代码replace它后,一切正常。
可以添加多个HorizontalScrollVIew视图或任何其他需要关注的视图。
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; } }
}