简体   繁体   English

android:ZoomPicker打破了onTouchListener

[英]android: ZoomPicker breaks onTouchListener

I've got a webview which makes use of the built in zoom controls, as follows: 我有一个使用内置缩放控件的webview,如下所示:

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

Note: this activates two main functions - pinch-to-zoom and invokeZoomPicker() (the latter is only called when a swiping action is done on the view, a simple touch doesn't enable it) 注意:这会激活两个主要功能 - 捏合缩放和invokeZoomPicker()(后者仅在视图上执行滑动操作时调用,简单触摸不启用它)


and i also want things to happen when touch events occur, using the following 并且我还希望在触摸事件发生时发生事情,使用以下内容

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

When the WebView loads, and I tap the screen, the log states "touched" every time I interact with the screen, as expected. 当WebView加载并点击屏幕时,每当我与屏幕交互时,日志都会按预期进行“触摸”。 However, if I do something that would set off invokeZoomPicker() (pinch to zoom doesn't seem to cause this problem, as long as the zoom widget doesn't appear), onTouchListener stops responding to my taps (even after a few seconds, when the widget disappears from view). 但是,如果我做了一些会引发invokeZoomPicker()的事情(捏缩放似乎不会导致这个问题,只要缩放小部件没有出现),onTouchListener就会停止响应我的点击(即使几秒钟后) ,当小部件从视图中消失时)。

To make sure it was invokeZoomPicker(), I edited the second segment of my code as follows: 为了确保它是invokeZoomPicker(),我编辑了我的代码的第二部分,如下所示:

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

This new onTouch method now only triggers once (as a result of which the zoomwidget appears on the view - and disappears a few seconds later), and then the onTouch method doesn't get called again until the view is reloaded - so it is definitely a problem with the invokeZoomPicker()/Zoom widget 这个新的onTouch方法现在只触发一次(因此zoomwidget出现在视图上 - 并在几秒钟后消失),然后在重新加载视图之前不会再次调用onTouch方法 - 所以它肯定是invokeZoomPicker()/ Zoom小部件的问题

Have I missed some vital piece of code that allows them to coexist, or do I just have to choose which one I can live without? 我是否错过了一些允许它们共存的重要代码,或者我只需要选择哪一个我可以不用的代码?

So after running into the same problem myself, I tried to make sense of some of these answers to no avail. 因此,在遇到同样的问题后,我试图理解其中一些答案无济于事。 The problem at hand is that once the user invokes scroll (not pinch-zoom) (at least for me...), the WebView instance loses its OnTouchListener reference. 手头的问题是,一旦用户调用滚动(不是缩放缩放)(至少对我来说......),WebView实例就会丢失其OnTouchListener引用。 How did I figure this out? 我怎么知道这个? Well... 好...

Webview inherits dispatchTouchEvent() from View. Webview从View继承dispatchTouchEvent()。 dispatchTouchEvent calls onTouch() (which is the function not firing that should) dispatchTouchEvent调用onTouch()(这是不应该触发的函数)

The reason why onTouch() wasn't getting called was, as I said before, that the WebView instance's OnTouchListener was getting set to null for some reason. 正如我之前所说,onTouch()没有被调用的原因是WebView实例的OnTouchListener由于某种原因被设置为null。 This can be seen by putting a breakpoint in View's dispatchTouchEvent() method 这可以通过在View的dispatchTouchEvent()方法中放置一个断点来看出

So to solve this, we extend WebView like so: 所以为了解决这个问题,我们像这样扩展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);
    }
}

And then we implement our OnTouchListener: 然后我们实现我们的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 will now fire even after zooming or scrolling 即使在缩放或滚动后,OnTouch现在也会触发

Try 尝试

youWebView.getSettings().setBuiltInZoomControls(false);

It's work for me. 这对我有用。

I had the same problem, but managed to solve it by setting the listener again in my extended WebView class: 我有同样的问题,但设法通过在我的扩展WebView类中再次设置监听器来解决它:

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

Unfortunately, now I have the opposite problem in that the zoom controls (the plus/minus widget) does no longer receive touch events. 不幸的是,现在我遇到了相反的问题,即缩放控件(正/负小部件)不再接收触摸事件。 There seems to be some exclusivity between having an OnTouchListener and zoom, at least in Android SDK level 8 (Froyo 2.2). 在使用OnTouchListener和缩放之间似乎存在一些排他性,至少在Android SDK等级8(Froyo 2.2)中。

This sounds like a bug to me, but would love to find a workaround. 这对我来说听起来像个错误,但是很想找到解决方法。

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

The workaround is pretty simple. 解决方法非常简单。 You have to create a custom class, that extends one of the ViewGroup subclasses like LinearLayout. 您必须创建一个自定义类,它扩展了一个ViewGroup子类,如LinearLayout。 Then override onInterceptTouchEvent - it will be called prior to ViewGroup child's onTouchEvent. 然后重写onInterceptTouchEvent - 它将在ViewGroup子项的onTouchEvent之前调用。 It is not very elegant to put a webview control into your custom ViewGroup subclass, and then insert it into activity's view hierarchy - where it is desired, but - it works. 将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);
    }


}

I had the same zoom issue as Stijn.V. 我有与Stijn.V相同的缩放问题。 I used the code in his answer but still had an issue with the touchListener sometimes being set to null. 我在他的回答中使用了代码,但仍然有一个问题,touchListener有时被设置为null。 Here's my full webview class, tested on Android 4.0 - 4.3 这是我的完整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;
    }
}

} }

For the sake of completeness here's how touchEvent is initialised in my calling activity 为了完整起见,这里是如何在我的调用活动中初始化touchEvent

bookWebview.setOnTouchListener(new View.OnTouchListener() {

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

I have encountered same problem, and i extended WebView and create my own ontouchlistener to avoid this bug. 我遇到了同样的问题,我扩展了WebView并创建了自己的ontouchlistener来避免这个bug。 For example: public class BookknowWebView extends WebView { 例如:公共类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;
}   

} }

Works perfectly fine for me. 对我来说效果很好。 Just use onTouchEvent(MotionEvent event) instead of onTouch(View v, MotionEvent event). 只需使用onTouchEvent(MotionEvent事件)而不是onTouch(View v,MotionEvent事件)。 Works even if setBuiltInZoomControls is set to true. 即使setBuiltInZoomControls设置为true也可以工作。

This is the closest I could come to a solution to this problem. 这是我能够最接近解决这个问题的方法。 I needed to set the input focus to the WebView whenever it was touched. 我需要在触摸时将输入焦点设置为WebView。 The only way I could do it was by extending WebView and overriding the onTouchEvent function. 我能做到的唯一方法是扩展WebView并覆盖onTouchEvent函数。 This function gets called even after Zooming is used in the WebView. 即使在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;
}

Don't forget that if you use XML to create your layout, you'll need to change "WebView" to your fully qualified packagename.NewWebView (otherwise you get a confusing ClassCastException if you try to do something like: 不要忘记,如果使用XML来创建布局,则需要将“WebView”更改为完全限定的packagename.NewWebView(否则,如果您尝试执行以下操作,则会遇到令人困惑的ClassCastException:

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

I think there is some exclusivity, for example, for a 500x500 web view and you zoom it in to 1000x1000, then you touched on it, now what position should it report? 我认为有一些排他性,例如,对于一个500x500的网页视图,你把它放大到1000x1000,然后你触及它,现在应该报告什么位置?

But I really need to get them working together. 但我真的需要让他们一起工作。

I had a similar problem where onTouch wouldn't get called after I used pinch to zoom . 我有一个类似的问题,在使用捏缩放后, onTouch不会被调用。 Inspired by jpeskin 's answer, this code worked for me (add it in the class that extends WebView): jpeskin的回答启发,这段代码对我有用 (将它添加到扩展WebView的类中):

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

update: 更新:

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

The touchListener is of the type android.view.View.OnTouchListener . touchListener的类型为android.view.View.OnTouchListener

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM