android:ViewPager和Horizo​​ntalScrollVIew

And*_*oob 30 events android scroll view touch

我有一个HorizontalScrollView内心ViewPager.我requestDisallowInterceptTouchEvent(true);为此设定 了HorizontalScrollViewViewPager仍有时会拦截触摸事件.是否有另一个命令我可以用来阻止View的父级和祖先拦截触摸事件?

注意:HorizontalScrollView只占屏幕的一半.

Fed*_*ede 35

我有同样的问题.我的解决方案是:

  1. 创建一个子类ViewPager并添加一个名为的属性childId.
  2. childId属性创建一个setter 并设置id的id HorizontalScrollView.
  3. onInterceptTouchEvent()在子类中重写,ViewPager如果childId属性大于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;
    }
}
Run Code Online (Sandbox Code Playgroud)

onCreate()方法中

viewPager.setChildId(R.id.horizontalScrollViewId);
adapter = new ViewPagerAdapter(this);
viewPager.setAdapter(adapter);
Run Code Online (Sandbox Code Playgroud)

希望这有帮助

  • 这次真是万分感谢!我确实做了一个修改.我不认为您需要在页面翻转时更新setChildId(),或者至少在使用FragmentPagerAdapter时更新.当用户更改页面时,视图消失,`findViewById(childId)`将消失.因此,你只需要调用`setChildId()`一次就可以释放`onPageChangeListener()`用于其他用途. (2认同)

And*_*oob 8

谢谢回复.我稍微修改了你的解决方案并设法使嵌套的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 毕竟你不是那么大的菜鸟 - 很好的解决方案. (4认同)

Vic*_*ias 7

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

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

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;
   }
}
Run Code Online (Sandbox Code Playgroud)

因此,如果您的ViewPager中有一个不同的View类,它也应该接收水平拖动,只需更改customCanScroll(View),这样您就可以在不应该截取触摸时返回.

如果还应检查当前视图的"可滚动性",则布尔checkV为true,这就是为什么我们也应该检查它.

希望这有助于解决此类未来的问题(或者如果有更好的解决方案,或Android平台的官方解决方案,请告诉我).


Rya*_*Hoo 6

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

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

首先,您需要了解其用法

ViewParent.requestDisallowInterceptTouchEvent(boolean),在父视图上调用此方法以指示它不应使用onInterceptTouchEvent(MotionEvent)拦截触摸事件.

然后,您需要拦截事件并确保您的Horizo​​ntalScrollView的父ViewGroup不会进一步调度事件.

因此,为您设置一个OnToushListener Horizo​​ntalScrollView.检测触摸并移动事件,然后将requestDisallowInterceptTouchEvent(true)设置为它的父(ViewPager或其他),以确保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;
}
Run Code Online (Sandbox Code Playgroud)


Ali*_*imi 5

这是另一个对我有用的解决方案,

创建自定义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;
    }



}
Run Code Online (Sandbox Code Playgroud)

然后将OnTouchListener添加到您的项目中,无论是Horizo​​ntalScrollView还是Gallery,还是其他任何您不希望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;
    }

});
Run Code Online (Sandbox Code Playgroud)