How can I get onclick event on webview in android?
Asked Answered
M

11

74

I want to know when the user clicks on webview but not on a hyperlink. On that click I want to show/hide a view of my activity that holds a webview. Any suggestion?

Madwort answered 25/2, 2011 at 11:54 Comment(2)
Hey Arslan, do you have an example of that you can post or link to?Dandruff
https://mcmap.net/q/270945/-android-singletap-onclick-in-webviewChandler
B
89

I took a look at this and I found that a WebView doesn't seem to send click events to an OnClickListener. If anyone out there can prove me wrong or tell me why then I'd be interested to hear it.

What I did find is that a WebView will send touch events to an OnTouchListener. It does have its own onTouchEvent method but I only ever seemed to get MotionEvent.ACTION_MOVE using that method.

So given that we can get events on a registered touch event listener, the only problem that remains is how to circumvent whatever action you want to perform for a touch when the user clicks a URL.

This can be achieved with some fancy Handler footwork by sending a delayed message for the touch and then removing those touch messages if the touch was caused by the user clicking a URL.

Here's an example:

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;
}
}

Breastbeating answered 26/2, 2011 at 7:18 Comment(10)
Thanks 4 ur time. But what about a javascript interface having a method attach to body by onClick... I use that it working.Madwort
You are also right in a case if we have no access to HTML data of page. Or if it is loading from a web. Thanks.Madwort
Is there any way to get control of webview contain? Actually i want to get the play/pause/stop/complete event of youtube video on webview. how could i achieve this?Dulcet
I don't know if it makes any difference in this case, but it should be noted that shouldOverrideUrlLoading() can be called during a redirect and is not always because of a user interaction with a link.Kenney
but the click event and touch event are two different things.When user click the webview onTouch of it does not calledFrazzled
The event is also triggered while scrolling.Geosphere
C.d, that can be fixed by replacing ACTION_DOWN to ACTION_UP. I found it to work a lot better in my ScrollView.Twig
I use in WebView dispatchTouchEvent( MotionEvent motionEvent), with next code: 'if( motionEvent.getAction() == MotionEvent.ACTION_MOVE) return true;' and else 'return false;'. This work for get click on any path of WebView and 'disable' moves.Rounding
Thanks, the solution works. Should better change ACTION_DOWN to ACTION_UP, as said by RealCasually (2 answers up).Vickery
Thanks. (Click on my webview) The solution on my RecyclerView Adapter: public boolean onTouch(View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_UP) {} }Consanguineous
D
39

You can implement an OnClickListener via OnTouchListener:

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;
        }
    });
Disport answered 3/2, 2014 at 14:47 Comment(0)
D
16

Hamidreza's solution almost worked for me.

I noticed from experimentation that a simple tap usually has 2-5 action move events. Checking the time between action down and up was simpler and behaved more like what I expected.

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;
    }
Dirkdirks answered 28/4, 2016 at 22:8 Comment(2)
Works much betterEsteresterase
Thank you so much, it took me a few hours to find a solution, and yours was the only one which actually worked.Erdrich
G
12

On Click event On webView works in onTouch like this:

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;                 
  }                       
});
Geosynclinal answered 27/3, 2017 at 12:40 Comment(1)
But this also clicks on webview. I mean activity is opening but click is also working on webview.Giustino
E
5

I have tried almost all the answers and some of them almost worked for me but none of these answers work perfectly. So here is my solution. For this solution, you will need to add onclick attribute in the HTML body tag. So if you can not modify the HTML file then this solution won't work for you.

Step 1: add onclick attribute in the HTML body tag like this:

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

Step 2: We can not perform any action on main thread from performClick method so need to add Handler class:

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

implement Handler.Callback to your class and the override 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;
}

Step 3: implement addJavascriptInterface in your app to handle click listener:

webView.addJavascriptInterface(new Object() {
    @JavascriptInterface
    public void performClick(String string) {
        handler.sendEmptyMessageDelayed(CLICK_ON_WEBVIEW, 0);
    }
}, "ok");
Erigena answered 9/7, 2020 at 14:51 Comment(0)
S
4

I think you can also use MotionEvent.ACTION_UP state, example:

@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;
}
Sclerotomy answered 3/4, 2014 at 10:41 Comment(0)
H
3

This works for me

webView.setOnTouchListener(new View.OnTouchListener() {
                            @Override
                            public boolean onTouch(View v, MotionEvent event) {
                                // Do what you want
                                return false;
                            }
                        });
Harken answered 19/5, 2015 at 8:37 Comment(3)
Sad, but not worked for me, onClick events are still missed.Vickery
Maybe you have another view consuming the touch event.Harken
How to enable click event again please help me sir,Haematosis
G
0

WebViewClient.shouldOverrideUrlLoading might be helpful. We are having a similar requirement in one of our app. Not tried yet.

Gestation answered 27/6, 2014 at 7:43 Comment(0)
T
0

Thats because its tied to the web view not the button. I had the same problem after implementing. The button had no affect but the page in the web view did.

Thermomotor answered 12/2, 2016 at 22:41 Comment(0)
V
0

I assume that there is a click when no action between DOWN and 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;
        }
    });
Varia answered 11/11, 2022 at 14:1 Comment(0)
V
0

Here is how to do it in 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
    }
}
Voluble answered 2/1, 2023 at 9:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.