如何在android中的webview上获取onclick事件?

问题描述 投票:0回答:12

我想知道用户何时单击网络视图而不是超链接。单击该按钮时,我想显示/隐藏包含网络视图的活动的视图。有什么建议吗?

android android-webview
12个回答
89
投票

我看了一下这个,发现

WebView
似乎没有将点击事件发送到
OnClickListener
。如果有人可以证明我错了或告诉我原因,那么我有兴趣听听。

我发现

WebView
会将触摸事件发送到
OnTouchListener
。它确实有自己的
onTouchEvent
方法,但我似乎只使用该方法得到
MotionEvent.ACTION_MOVE

因此,鉴于我们可以在已注册的触摸事件侦听器上获取事件,剩下的唯一问题是如何在用户单击 URL 时规避您想要对触摸执行的任何操作。

这可以通过一些奇特的

Handler
步法来实现,方法是发送触摸延迟消息,然后如果触摸是由用户单击 URL 引起的,则删除这些触摸消息。

这是一个例子:

public class WebViewClicker extends Activity implements OnTouchListener, Handler.Callback {

private static final int CLICK_ON_WEBVIEW = 1;
private static final int CLICK_ON_URL = 2;

private final Handler handler = new Handler(this);

private WebView webView;
private WebViewClient client;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.web_view_clicker);
    
    webView = (WebView)findViewById(R.id.web);
    webView.setOnTouchListener(this);

    client = new WebViewClient(){ 
        @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { 
            handler.sendEmptyMessage(CLICK_ON_URL);
            return false;
        } 
    }; 
    
    webView.setWebViewClient(client);
    webView.setVerticalScrollBarEnabled(false);
    webView.loadUrl("http://www.example.com");
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (v.getId() == R.id.web && event.getAction() == MotionEvent.ACTION_DOWN){
        handler.sendEmptyMessageDelayed(CLICK_ON_WEBVIEW, 500);
    }
    return false;
}

@Override
public boolean handleMessage(Message msg) {
    if (msg.what == CLICK_ON_URL){
        handler.removeMessages(CLICK_ON_WEBVIEW);
        return true;
    }
    if (msg.what == CLICK_ON_WEBVIEW){
        Toast.makeText(this, "WebView clicked", Toast.LENGTH_SHORT).show();
        return true;
    }
    return false;
}
}


39
投票

您可以通过OnTouchListener实现OnClickListener:

webView.setOnTouchListener(new View.OnTouchListener() {

        public final static int FINGER_RELEASED = 0;
        public final static int FINGER_TOUCHED = 1;
        public final static int FINGER_DRAGGING = 2;
        public final static int FINGER_UNDEFINED = 3;

        private int fingerState = FINGER_RELEASED;


        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {

            switch (motionEvent.getAction()) {

                case MotionEvent.ACTION_DOWN:
                    if (fingerState == FINGER_RELEASED) fingerState = FINGER_TOUCHED;
                    else fingerState = FINGER_UNDEFINED;
                    break;

                case MotionEvent.ACTION_UP:
                    if(fingerState != FINGER_DRAGGING) {
                        fingerState = FINGER_RELEASED;

                        // Your onClick codes

                    }
                    else if (fingerState == FINGER_DRAGGING) fingerState = FINGER_RELEASED;
                    else fingerState = FINGER_UNDEFINED;
                    break;

                case MotionEvent.ACTION_MOVE:
                    if (fingerState == FINGER_TOUCHED || fingerState == FINGER_DRAGGING) fingerState = FINGER_DRAGGING;
                    else fingerState = FINGER_UNDEFINED;
                    break;

                default:
                    fingerState = FINGER_UNDEFINED;

            }

            return false;
        }
    });

17
投票

Hamidreza 的解决方案几乎对我有用。

我从实验中注意到,一个简单的点击通常有 2-5 个动作移动事件。 检查向下和向上操作之间的时间更简单,并且表现更像我的预期。

private class CheckForClickTouchLister implements View.OnTouchListener {
    private final static long MAX_TOUCH_DURATION = 100;

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

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                m_DownTime = event.getEventTime(); //init time

                break;

            case MotionEvent.ACTION_UP:
                if(event.getEventTime() - m_DownTime <= MAX_TOUCH_DURATION)
                    //On click action

                break;

            default:
                break; //No-Op

        }
        return false;
    }

12
投票

On Click 事件 On webView 在 onTouch 中的工作方式如下:

imagewebViewNewsChart.setOnTouchListener(new View.OnTouchListener(){

  @Override   
  public boolean onTouch(View v, MotionEvent event) { 
    if (event.getAction()==MotionEvent.ACTION_MOVE){                        
       return false;     
    }

    if (event.getAction()==MotionEvent.ACTION_UP){    
        startActivity(new Intent(this,Example.class));                

    } 

    return false;                 
  }                       
});

5
投票

我已经尝试了几乎所有的答案,其中一些几乎对我有用,但这些答案都不能完美地工作。这是我的解决方案。对于此解决方案,您需要在 HTML body 标记中添加

onclick
属性。因此,如果您无法修改 HTML 文件,那么此解决方案将不适用于您。

第1步:在HTML body标签中添加

onclick
属性,如下所示:

<body onclick="ok.performClick(this.value);">
    <h1>This is heading 1</h1>
    <p>This is para 1</p>
</body>

第2步:我们无法通过

performClick
方法在主线程上执行任何操作,因此需要添加
Handler
类:

private final Handler handler = new Handler(this); // class-level variable 
private static final int CLICK_ON_WEBVIEW = 1; // class-level variable 

在您的班级中实施

Handler.Callback
并覆盖
handleMessage

@Override
public boolean handleMessage(Message message) {
    if (message.what == CLICK_ON_WEBVIEW) {
        Toast.makeText(getActivity(), "WebView clicked", Toast.LENGTH_SHORT).show();
        return true;
    }
    return false;
}

第 3 步: 在您的应用程序中实现

addJavascriptInterface
来处理点击侦听器:

webView.addJavascriptInterface(new Object() {
    @JavascriptInterface
    public void performClick(String string) {
        handler.sendEmptyMessageDelayed(CLICK_ON_WEBVIEW, 0);
    }
}, "ok");

4
投票

我想你也可以使用MotionEvent.ACTION_UP状态,例如:

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (v.getId()) {
    case R.id.iv:
        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (isheadAndFootShow == false) {
                headLayout.setVisibility(View.VISIBLE);
                footLayout.setVisibility(View.VISIBLE);
                isheadAndFootShow = true;
            } else {
                headLayout.setVisibility(View.INVISIBLE);
                footLayout.setVisibility(View.INVISIBLE);
                isheadAndFootShow = false;
            }
            return true;
        }
        break;
    }

    return false;
}

3
投票

这对我有用

webView.setOnTouchListener(new View.OnTouchListener() {
                            @Override
                            public boolean onTouch(View v, MotionEvent event) {
                                // Do what you want
                                return false;
                            }
                        });

0
投票

WebViewClient.shouldOverrideUrlLoading
可能会有所帮助。我们的一个应用程序也有类似的要求。还没试过。


0
投票

那是因为它与网络视图而不是按钮相关。实施后我也遇到了同样的问题。该按钮没有影响,但 Web 视图中的页面有影响。


0
投票

我认为当 DOWN 和 UP 之间没有任何动作时,有一个点击。

    lastTouchAction = -1;

    myWebView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            if(event.getAction() == MotionEvent.ACTION_UP && lastTouchAction == MotionEvent.ACTION_DOWN){
                //do something
            }

            lastTouchAction = event.getAction();

            return false;
        }
    });

0
投票

以下是如何在 Android Compose UI 中执行此操作:

@Composable
private fun MyScreen(url: String, onWebLinkClicked: (String) -> Unit) {
    AndroidView(
        factory = {
            WebView(it).apply {
                webViewClient = CustomWebViewClient(onWebLinkClicked)
                loadUrl(url)
            }
        },
        update = { it.loadUrl(url) }
    )
}

private class CustomWebViewClient(val onWebLinkClicked: (String) -> Unit) : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
        onWebLinkClicked(request.url.toString())
        return true
    }
}

0
投票

实际上现在容易多了。可以通过重写 WebViewClient 的

shouldOverrideUrlLoading
方法来监听每个点击的 url。下面的例子:

@SuppressLint("SetJavaScriptEnabled") // called in onViewCreated
private fun setupWebView() = with(binding.webView) {
    webViewClient = object : WebViewClient() {
        override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
            val path = request.url.path ?: return false

            if (path.contains(SUCCESS_PATH) || path.contains(FAILURE_PATH)
            ) {
                // your click action here 
                return true // make sure to return true if url click hanlded
            }
            return false
        }
    }
    settings.apply {
        javaScriptEnabled = true
        domStorageEnabled = true
        javaScriptCanOpenWindowsAutomatically = true
        allowContentAccess = true
    }
    loadUrl(yourWebViewUrl)
}
© www.soinside.com 2019 - 2024. All rights reserved.