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?
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;
}
}
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;
}
});
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;
}
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;
}
});
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");
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;
}
This works for me
webView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// Do what you want
return false;
}
});
WebViewClient.shouldOverrideUrlLoading
might be helpful. We are having a similar requirement in one of our app. Not tried yet.
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.
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;
}
});
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
}
}
© 2022 - 2024 — McMap. All rights reserved.