Arslan Anwar
Arslan Anwar

Reputation: 18746

How can I get onclick event on webview in android?

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?

Upvotes: 74

Views: 144877

Answers (12)

Temur Isroilov
Temur Isroilov

Reputation: 596

Actually now it much easier. It's possible to listen every clicked url by overriding shouldOverrideUrlLoading method of WebViewClient. Example below:

@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)
}

Upvotes: 0

JJD
JJD

Reputation: 51804

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

Upvotes: 0

adenizc
adenizc

Reputation: 421

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

Upvotes: 0

Faisal Shaikh
Faisal Shaikh

Reputation: 4138

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");

Upvotes: 5

Louth
Louth

Reputation: 12346

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

Upvotes: 89

Raza Baloch
Raza Baloch

Reputation: 344

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

Upvotes: 12

bduhbya
bduhbya

Reputation: 430

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

Upvotes: 17

FranticCity
FranticCity

Reputation: 1

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.

Upvotes: 0

SpyZip
SpyZip

Reputation: 5540

This works for me

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

Upvotes: 3

yogiam
yogiam

Reputation: 168

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

Upvotes: 0

wangzhengyi
wangzhengyi

Reputation: 876

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

Upvotes: 4

Hamidreza Hosseinkhani
Hamidreza Hosseinkhani

Reputation: 752

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

Upvotes: 39

Related Questions