android:ZoomPicker打破了onTouchListener

时间:2010-12-25 02:26:05

标签: android webview zoom ontouchlistener

我有一个使用内置缩放控件的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加载并点击屏幕时,每次我与屏幕交互时,日志都会按预期显示“已触摸”。但是,如果我做了一些会引发invokeZoomPicker()的事情(捏缩放似乎不会导致这个问题,只要缩放小部件没有出现),onTouchListener就会停止响应我的点击(即使几秒钟后) ,当小部件从视图中消失时)。

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

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

这个新的onTouch方法现在只触发一次(因此zoomwidget出现在视图上 - 并在几秒钟后消失),然后在重新加载视图之前不会再次调用onTouch方法 - 所以这肯定是invokeZoomPicker()/ Zoom小部件的问题

我是否错过了一些允许他们共存的重要代码,或者我只需要选择一个我可以不用的代码?

11 个答案:

答案 0 :(得分:3)

因此,在遇到同样的问题后,我试图理解其中一些答案无济于事。手头的问题是,一旦用户调用滚动(不是缩放缩放)(至少对我来说......),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也会启动

答案 1 :(得分:2)

我有同样的问题,但设法通过在扩展的WebView类中再次设置监听器来解决它:

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

不幸的是,现在我遇到了相反的问题,即缩放控件(加/减小部件)不再接收触摸事件。在使用OnTouchListener和缩放之间似乎存在一些排他性,至少在Android SDK等级8(Froyo 2.2)中。

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

答案 2 :(得分:2)

尝试

youWebView.getSettings().setBuiltInZoomControls(false);

这对我有用。

答案 3 :(得分:1)

一个肮脏的解决方案是覆盖Web视图顶部的隐形视图并检测其中的触摸,您必须区分是否消耗了触摸,或者返回false以将触摸传递给底层Web视图。

答案 4 :(得分:1)

解决方法非常简单。 您必须创建一个自定义类,它扩展了一个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);
    }


}

答案 5 :(得分:0)

这是我能找到解决这个问题的最接近的方法。我需要在触摸时将输入焦点设置为WebView。我能做到的唯一方法是扩展WebView并覆盖onTouchEvent函数。即使在WebView中使用了Zooming,也会调用此函数。

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”更改为完全限定的packagename.NewWebView(否则,如果您尝试执行以下操作,则会出现令人困惑的ClassCastException:

      webView = (NewWebView) findViewById(R.id.new_web_view);

答案 6 :(得分:0)

我认为有一些排他性,例如,对于500x500的网络视图,你将它放大到1000x1000,然后你触及它,现在应该报告什么位置?

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

答案 7 :(得分: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

答案 8 :(得分: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);
        }
    });

答案 9 :(得分:0)

我遇到了同样的问题,我扩展了WebView并创建了自己的ontouchlistener来避免这个bug。例如: 公共类BookknowWebView扩展了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;
}   

}

答案 10 :(得分:0)

对我来说效果很好。只需使用onTouchEvent(MotionEvent事件)而不是onTouch(View v,MotionEvent事件)。即使setBuiltInZoomControls设置为true也可以工作。