Android:ZoomPicker破坏了onTouchListener

11

我有一个使用内置缩放控件的Webview,如下:

wv = new WebView(this);
wv.getSettings().setBuiltInZoomControls(true);

注意:这将激活两个主要功能 - 捏合缩放和invokeZoomPicker()(只有在视图上进行滑动操作时才会调用后者,简单触摸无法启用它)


当发生触摸事件时,我还希望发生以下事情,使用以下方式:

wv.setOnTouchListener(new View.OnTouchListener() {  
    public boolean onTouch(View v, MotionEvent event) {
        Log.i("touch", "touched!");
        return false;
    }
});

当WebView加载时,如果我点击屏幕,日志记录会像预期的那样每次与屏幕交互时都会显示“touched”。但是,如果我执行会引发invokeZoomPicker()的某些操作(捏合缩放似乎不会导致此问题,只要缩放小部件不出现),onTouchListener 将停止响应我的轻触(即使在小部件从视图中消失几秒钟后也是如此)。

为了确保它是invokeZoomPicker(),我编辑了代码的第二个部分如下:

wv.setOnTouchListener(new View.OnTouchListener() {  
    public boolean onTouch(View v, MotionEvent event) {
        wv.invokeZoomPicker();
        Log.i("touch", "touched!");
        return false;
    }
});

这个新的onTouch方法现在只会触发一次(因此缩放小部件出现在视图上 - 并在几秒钟后消失),然后onTouch方法不会再次调用,直到重新加载视图 - 因此这绝对是invokeZoomPicker()/Zoom widget的问题。

我错过了一些允许它们共存的重要代码吗,还是我只能选择其中一个并放弃另一个?


不幸的是,我还没有想出来。 - tabjsina
11个回答

4
因为我自己遇到了同样的问题,所以我试图理解一些答案,但都无法解决。实际问题是,一旦用户滚动(而不是捏合缩放)(至少对于我来说…),WebView实例就会失去其OnTouchListener引用。我是如何发现这一点的?那么...

Webview从View继承dispatchTouchEvent()。 dispatchTouchEvent调用onTouch()(它应该是未触发的函数)

onTouch()未被调用的原因是,正如我之前所说,WebView实例的OnTouchListener由于某种原因被设置为null。这可以通过在View的dispatchTouchEvent()方法中设置断点来看到。

因此,我们可以通过扩展WebView来解决这个问题:

import android.content.Context;
import android.util.AttributeSet;
import android.webkit.WebView;

public class TouchWebView extends WebView {

    WebTouchListener wtl;

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

    public TouchWebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

    public void resetTouchListener() {

        if(this.wtl == null) {
            this.wtl = new WebTouchListener();
        }
        this.setOnTouchListener(wtl);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        this.resetTouchListener();
        return super.dispatchTouchEvent(event);
    }
}

然后我们实现OnTouchListener:

import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.webkit.WebView;

public class WebTouchListener implements OnTouchListener {

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        WebView.HitTestResult hr = ((TouchWebView)v).getHitTestResult();
        //Log.i(TAG, "getExtra = "+ hr.getExtra() + "\t\t Type=" + hr.getType());

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            System.out.println(hr.getExtra() + " " + hr.getType());
        }

        // TODO Auto-generated method stub
        return false;
    }


}

现在即使在缩放或滚动后,OnTouch事件也会被触发。


2
解决方法非常简单。您需要创建一个自定义类,它继承了ViewGroup子类之一,如LinearLayout。然后覆盖onInterceptTouchEvent - 它将在ViewGroup子项的onTouchEvent之前被调用。将WebView控件放入自定义ViewGroup子类中并将其插入到活动的视图层次结构中可能不是很优雅,但这样做是可以实现的。
private class OwnedLayout extends LinearLayout
{
    protected OwnedLayout(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    protected OwnedLayout(Context context)
    {
        super(context);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        //Put Your code here
        return super.onInterceptTouchEvent(ev);
    }


}

2

我也遇到了同样的问题,但是通过在我的扩展WebView类中重新设置监听器来解决了它:

public void invalidate() {
    super.invalidate();
    setOnTouchListener(this);
}

很不幸,现在我有相反的问题,缩放控件(加号/减号小部件)不再接收触摸事件。在Android SDK 8级(Froyo 2.2)中,在具有OnTouchListener和缩放之间存在某种排他性。

对我来说,这听起来像是一个bug,但我很想找到一个解决方法。


1
尝试
youWebView.getSettings().setBuiltInZoomControls(false);

这对我很有效。


1
一个不太好的解决方法是在你的网页视图上面覆盖一个无形视图并检测那里的触摸,然后你必须区分触摸是否被消耗,或者返回 false 以将触摸传递到底层的网页视图。

这对我非常有效。我只是创建了一个 <View/> 并将其放置在 <RelativeLayout/> 内部的 <WebView/> 顶部。然后,我设置了 ViewonTouchListener 并使其返回 false - BVB

0

我曾经遇到过类似的问题,当我使用捏合缩放后,onTouch方法不再被调用。受到jpeskin答案的启发,以下代码对我有效(将其添加到扩展WebView的类中):

@Override
public boolean onTouchEvent(MotionEvent event) {            
    boolean consumed = super.onTouchEvent(event);               
    onTouch(this, event);           
    return consumed;
}

更新:

@Override
public boolean onTouch(View v, MotionEvent event) {
    return touchListener.onTouch(v, event);
}

touchListener 是类型为 android.view.View.OnTouchListener 的。


在继承自WebView的类中,你的代码无法编译 -- 它说找不到onTouch方法。你是否在WebView子类中实现了onTouch方法?如果是的话,用注释替换onTouch()调用会使你的示例更清晰。 - Lorne Laliberte
我已经检查过了,在继承 WebView 的类中确实有一个 onTouch() 方法,所以这个类实现了 OnTouchListener 接口。 - Stijn.V

0
这是我能够接近解决此问题的方法。每当WebView被触摸时,我需要将输入焦点设置为它。唯一的方法是通过扩展WebView并覆盖onTouchEvent函数来实现。即使在WebView中使用缩放后,该函数仍会被调用。
public class NewWebView extends WebView {

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

public NewWebView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

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

@Override
public boolean onTouchEvent(MotionEvent ev) {
    boolean consumed = super.onTouchEvent(ev);

    if (isClickable())
        if (ev.getAction() == MotionEvent.ACTION_DOWN)
        {
            if (!hasFocus())
                requestFocus();
        }
    return consumed;
}

不要忘记,如果您使用XML创建您的布局,则需要将“WebView”更改为您完全限定的包名称NewWebView(否则,如果您尝试执行类似以下操作,则会获得令人困惑的ClassCastException:
      webView = (NewWebView) findViewById(R.id.new_web_view);

抱歉没有早点处理,但我终于有机会测试这段代码了。不幸的是,这种方法无法使onTouch再次工作。 - tabjsina

0

我遇到了与Stijn.V相同的缩放问题。我使用了他的答案中的代码,但有时仍会出现touchListener被设置为null的问题。这是我的完整webview类,在Android 4.0-4.3上进行了测试。

public class BookWebView extends WebView implements OnTouchListener {

private OnTouchListener mTouchListener;

public BookWebView(Context context) {
    super(context);

}

public BookWebView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

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

@Override
public boolean onTouchEvent(MotionEvent event) {            
    boolean consumed = super.onTouchEvent(event);               
    onTouch(this, event);           
    return consumed;
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    return mTouchListener.onTouch(v, event);
}

@Override
public void setOnTouchListener(OnTouchListener l) {
    super.setOnTouchListener(l);
    if(l != null){
        mTouchListener = l;
    }
}

}

为了完整起见,这是在我的调用活动中初始化touchEvent的方法。
bookWebview.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return mGestureDetector.onTouchEvent(event);
        }
    });

0

我遇到了相同的问题,并且我扩展了WebView,并创建了自己的ontouchlistener来避免这个 bug。例如: public class BookknowWebView extends WebView {

private GestureDetector gestureDetector;
    private OnTouchListener mListener;

/**
 * @param context
 * @param attrs
 * @param defStyle
 */
public BookknowWebView(Context context) {
    super(context);
}

/**
 * @param context
 * @param attrs
 * @param defStyle
 */
public BookknowWebView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

/**
 * @param context
 * @param attrs
 * @param defStyle
 */
public BookknowWebView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public void setBookknowOnTouchListener(OnTouchListener l){
    mListener = l;
}

/* 
 * @see android.webkit.WebView#onTouchEvent(android.view.MotionEvent)
 */
@Override
public boolean onTouchEvent(MotionEvent ev) {
     mListener.onTouch(this, ev);       
    return gestureDetector.onTouchEvent(ev) || super.onTouchEvent(ev);
}

public void setGestureDetector(GestureDetector gestureDetector) {
    this.gestureDetector = gestureDetector;
}   

}


0

我认为有一些独占性,例如,对于一个500x500的Web视图,如果您将其缩放到1000x1000,然后在其上触摸,那么它应该报告什么位置?

但我真的需要让它们一起工作。


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