Android Webview:防止触摸手势传递给父ViewPager

21
我有一个包含许多子视图的viewpager; 每个子视图都是一个webview。每个webview都有一些HTML对象,用户可以与之交互; 例如,一个可以在滑动手势上工作的幻灯片或者一个可拖动的圆形,用户可以将其移动到HTML画布上。
问题在于,当用户在这些HTML对象上执行手势时,viewpager会滚动到下一个视图。我希望当用户与它们交互时(viewpager不滚动),HTML对象能够正常工作,并且当用户在其他位置滑动时,viewpager会滚动。我该怎么做?
P.S. 我在HTML幻灯片的JavaScript中使用了event.preventDefault()和event.stopPropagation(),希望webview不会将触摸事件传递给父视图viewpager。

你可以查看类似的线程:https://dev59.com/iGsz5IYBdhLWcg3wmpP0 - GrIsHu
1
谢谢@GrIsHu,但这对这种情况不起作用。那个答案覆盖了HTML网页视图大于viewpager可见区域的情况。我已经解决了这个问题。 - Hoang Huynh
你们支持的最低版本的Android是什么?你们能控制HTML吗?如果需要,你们能改变它吗? - Juangcg
@Juangcg 我支持Android 2.3及更高版本。而且我可以更改HTML的所有内容。 - Hoang Huynh
@HoangHuynh 你解决了这个问题吗? - Boa
显示剩余2条评论
3个回答

5

覆盖你的ViewPager"canScroll"方法,只有在视图不是WebView的实例时才允许滚动。

示例:

public class MyViewPager extends ViewPager {

    public MyViewPager (Context context) {
        super(context);
    }

    public MyViewPager (Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if(v instanceof WebView){
            return true;
        }
        return super.canScroll(v, checkV, dx, x, y);
    }

}

7
问题在于当用户在 WebView 中滑动时,如果超出 HTML 幻灯片的范围但仍在 WebView 中,则ViewPager 仍应滚动。 - Hoang Huynh

3
创建自己的ViewPager子类并重写canScroll方法如下。
class MyViewPager extends ViewPager {
...

@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
    if (isInsideSlideShow(x,y)) {
        return true; // allow the slide show its own scrolling
    } else {
        return false; // ViewPager scrolls
    }
}

你当然需要知道屏幕的哪个部分被幻灯片覆盖,这个知识必须在isInsideSlideShow方法中实现。
如果你不能得到幻灯片的x/y坐标,另一种解决方案可能是使用手势,从视图的边界开始作为翻页手势,而在更内部的区域开始作为幻灯片手势。
我正在为一个显示地图和图表的视图页面使用这种方法。两者都支持自己的平移。但当用户在左侧或右侧边界开始手势时,整个地图或图表都会被滑动开。
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        int width = getWidth();
        int slideWidth = Math.round(width * 0.15f);
        if (x < slideWidth || x > width - slideWidth) {
            return false;
        }
        return true;
}

1
谢谢,这是我实际使用的解决方法,但我需要比这更可靠的解决方案——因为用户可以与我的 Webview 中的 HTML 交互的区域可能会发生变化(例如,用户可以在 Webview 中拖动 HTML 对象)。 - Hoang Huynh
所以你需要以某种方式获取幻灯片演示的当前坐标。我不确定,但使用jQuery应该是可能的。 - user2808624
谢谢,这就是我正在做的事情,但我正在寻找一个本地解决方案,不涉及HTML的更改。 - Hoang Huynh
这与您对@Juangcg的评论有些矛盾:引用:“我可以更改HTML的所有内容”。有点困惑... - user2808624
抱歉给您带来了误导性的信息。我可以更改HTML,但(目前)这对我来说不是一个足够好的解决方案。我的HTML可能包含许多可拖动的对象,用户可以在HTML画布上移动它们。不断计算和更新这些对象的位置并将它们发送回Android似乎目前不太稳定和卡顿。 - Hoang Huynh
显示剩余3条评论

2

我的想法是实现一个JavaScript函数来决定哪些部分需要滚动:

function checkScroll(x, y){
    var o = document.elementFromPoint(x, y);
    result = $('div.swiper-container').find(o).length;
    MyAndroidInterface.processReturnValue(result);
}

接着覆盖这两个方法:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    @Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
        homepage.callJavascript("checkScroll(" + Math.round(ev.getX()) + "," + Math.round(ev.getY()) + ")");
        return super.onTouchEvent(ev);
    case MotionEvent.ACTION_MOVE:
        if (homepage.scrollSlideshowLock())
            return false;

你在重写哪些视图方法?你能修复一下代码片段吗?我的意思是,它缺少一些部分……onTouch方法实际上是否在onIntercept方法内部? - Geraldo Neto
1
抱歉,我完全忘记了安卓 :) - ropo
没问题。谢谢。 - Geraldo Neto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接