Webview Getting Rid Of Double Tap Zoom.
Solution 1:
There are two methods to achieve your goal:
Method 1
Implement the GestureDetector.OnDoubleTapListener
like this:
@OverridepublicbooleanonSingleTapConfirmed(MotionEvent e) {
returnfalse; //Nothing
}
@OverridepublicbooleanonDoubleTap(MotionEvent e) {
//Indicates that this implementation has handled the double tap.returntrue;
}
@OverridepublicbooleanonDoubleTapEvent(MotionEvent e) {
//Indicates that this implementation has handled the double tap.returntrue;
}
and attach it to your GestureDetector
like this:
gestureDetector.setOnDoubleTapListener(this);
Method 2
You can also use the WebSettings.setUseWideViewPort(false);
and calculate the size of your view manually.
These methods should help you to achieve non-zoomable webviews that display everything.
publicintgetWindowWidth(Activity activity) {
Displaydisplay= ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Pointsize=newPoint();
display.getSize(size);
intwidth= size.x;
return width;
}
publicintgetInitialScale(Activity activity, int websiteWidth) {
return (getWindowWidth(activity) / websiteWidth) * 100;
}
Solution 2:
There's a fantastic solution for your issue, based on Javascript (so you'll have to have access to the HTML/JS code in the remote side, if it's the case).
Using the FastClick library, all you need to do is to add the .js file and then call it:
<scripttype="application/javascript"src="fastclick.js"></script><scriptlanguage="javascript">window.addEventListener('load', function() {
FastClick.attach(document.body);
}, false);
</script>
This will get rid of the double tap zoom, and there's still (in my opinion) a huge bonus: all taps get 0.3 seconds faster, due to the fact the system doesn't have to wait anymore for a double tap! Check this example on Android to see the difference: Practical Example
Well, I don't know if this solution will fit in your case, but it was a perfect solution for my Webview projects. Hope it helps!
ps1: you have to add the code above in all pages and frames
ps2: the pinch zoom will keep working normally
Solution 3:
You need to override OnTouchListener on your WebView by
wv.setOnTouchListener(this);
and inside method onTouch just check that if it detect double tab then ignore the zoom in webview by force to return true
@OverridepublicbooleanonTouch(View v, MotionEvent event) {
// TODO Auto-generated method stubonTouchEvent(event);
if (doubletab)
returntrue;
returnfalse;
}
You can see full code like this: MainActivity.java
package com.example.testwebview;
import android.os.Bundle;
import android.app.Activity;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.View.OnTouchListener;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.TextView;
publicclassMainActivityextendsActivityimplementsOnGestureListener, OnTouchListener, GestureDetector.OnDoubleTapListener
{
TextView tv;
WebView wv;
GestureDetector gd;
boolean doubletab = false;
@OverridepublicvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gd = newGestureDetector(this);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.textView1);
wv = (WebView)findViewById(R.id.webView1);
WebSettings setting = wv.getSettings();
setting.setBuiltInZoomControls(false);
setting.setSupportZoom(false);
setting.setUseWideViewPort(true);
setting.setLoadWithOverviewMode(true);
wv.setOnTouchListener(this);
wv.loadUrl("http://www.sanook.com");
}
@OverridepublicbooleanonDoubleTap(MotionEvent arg0) {
tv.setText("double tap");
doubletab = true;
// TODO Auto-generated method stubreturnfalse;
}
@OverridepublicbooleanonDoubleTapEvent(MotionEvent arg0) {
tv.setText("double tap event");
doubletab = true;
// TODO Auto-generated method stubreturnfalse;
}
@OverridepublicbooleanonSingleTapConfirmed(MotionEvent arg0) {
tv.setText("single tap confirm");
doubletab = false;
// TODO Auto-generated method stubreturnfalse;
}
@OverridepublicbooleanonTouchEvent(MotionEvent me)
{
return gd.onTouchEvent(me);
}
@OverridepublicbooleanonDown(MotionEvent arg0) {
tv.setText("down");
doubletab = false;
// TODO Auto-generated method stubreturnfalse;
}
@OverridepublicbooleanonFling(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
tv.setText("fling");
doubletab = false;
// TODO Auto-generated method stubreturnfalse;
}
@OverridepublicvoidonLongPress(MotionEvent arg0) {
tv.setText("long press");
doubletab = false;
// TODO Auto-generated method stub
}
@OverridepublicbooleanonScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
tv.setText("scroll");
doubletab = false;
// TODO Auto-generated method stubreturnfalse;
}
@OverridepublicvoidonShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
tv.setText("show press");
doubletab = false;
}
@OverridepublicbooleanonSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
tv.setText("single tab up");
doubletab = false;
returnfalse;
}
@OverridepublicbooleanonTouch(View v, MotionEvent event) {
// TODO Auto-generated method stubonTouchEvent(event);
if (doubletab)
returntrue;
returnfalse;
}
}
and activity_main.xml
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent" ><TextViewandroid:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_alignParentRight="true"android:layout_alignParentTop="true"android:text="TextView" /><WebViewandroid:id="@+id/webView1"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:layout_below="@+id/textView1" /></RelativeLayout>
don't forget to add permission in manifest.xml
<uses-permissionandroid:name="android.permission.INTERNET" />
Solution 4:
Another approach (the only one that worked for me) would be to simulate distant intermediate taps between double taps so that the WebView doesn't recongnize them as consequent. Negative coordinates can be used for this purpose, although anything less than -1 would slow down or even break the process. So we need at least two points, say (0, -1) and (2*d+1, -1) where d is the maximum distance between taps for them to be considered double tap.
webView.setOnTouchListener(new View.OnTouchListener() {
privatelong lastUp = -1000;
privatefloat lastDownX = -1000;
privatefloat lastDownY = -1000;
privateint dtDistance = 0;
privateint dtDistanceSquared = 0;
privatelong dtTime = 0;
privatevoidperformTap(View v, int x, int y, long t) {
MotionEvent e_down = MotionEvent.obtain(t, t, MotionEvent.ACTION_DOWN, x, y, 0);
v.dispatchTouchEvent(e_down);
e_down.recycle();
MotionEvent e_up = MotionEvent.obtain(t, t, MotionEvent.ACTION_UP, x, y, 0);
v.dispatchTouchEvent(e_up);
e_up.recycle();
}
privateintgetRemoteX(float x) {
return Math.round(x > dtDistance + 0.5 ? 0 : 2 * dtDistance + 1);
}
private boolean inRadius(int x0, int y0, float x1, float y1) {
boolean result = (x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1) <= dtDistanceSquared;
return result;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getY() >= 0) // Otherwise it's a fake tap we simulated
{
if (dtTime == 0)
{
dtDistance = ViewConfiguration.get(v.getContext()).getScaledDoubleTapSlop(); // Maximum distance between taps for them to be considered double tap
dtDistanceSquared = dtDistance * dtDistance;
dtTime = ViewConfiguration.getDoubleTapTimeout(); // Maximum time elapsed between taps for them to be considered double tap
}
switch (event.getAction())
{
case MotionEvent.ACTION_UP:
lastUp = event.getEventTime();
break;
case MotionEvent.ACTION_DOWN:
long t = event.getEventTime();
if (t - lastUp < dtTime * 4/3) // Very rarely just (t - lastUp <= dtTime) doesn't work
{
int x = getRemoteX(event.getX());
if (inRadius(x, -1, lastDownX, lastDownY))
performTap(v, getRemoteX(lastDownX), -1, t); // Otherwise our fake tap would constitute a double tap with the previous real tap
performTap(v, x, -1, t);
}
lastDownX = event.getX();
lastDownY = event.getY();
break;
}
}
returnfalse;
}
});
Solution 5:
If possible, replace the static meta tag in your html:
<script>var meta = document.createElement("meta");
meta.setAttribute('name','viewport');
meta.setAttribute('content','width=device-width, user-scalable=no');
document.getElementsByTagName('head')[0].appendChild(meta);
</script>
Additionally you can use a nice script: FastClick It won't wait for tap events so its faster.
<scripttype="application/javascript"src="fastclick.js"></script><scriptlanguage="javascript">window.addEventListener('load', function() {
FastClick.attach(document.body);
}, false);
</script>
Then set a double tap listener to your gesture detector. (in custom WebView)
gestureDetector.setOnDoubleTapListener(newOnDoubleTapListener() {
@OverridepublicbooleanonSingleTapConfirmed( MotionEvent e ) {
returnfalse;
}
@OverridepublicbooleanonDoubleTapEvent( MotionEvent e ) {
returntrue;
}
@OverridepublicbooleanonDoubleTap( MotionEvent e ) {
returntrue;
}
});
Override the onTouchEvent method (in custom WebView):
@Override
public boolean onTouchEvent( MotionEvent event) {
boolean gestureHandled = gestureDetector.onTouchEvent(event);
int actionMask = event.getActionMasked() & MotionEvent.ACTION_MASK;
int index = ( event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int pointId = event.getPointerId(index);
// ignore move eventsif (actionMask == MotionEvent.ACTION_MOVE) {
return super.onTouchEvent(event);
}
// cancel detected double tapsif (gestureDetector.onTouchEvent(event)) {
event.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(event);
returntrue;
}
// if you want to ignore multi touch events/tapsif (pointId != 0) {
System.out.println("KEY multiple points detected");
returntrue;
}
// use single tapsif (event.getAction() == MotionEvent.ACTION_UP) {
event.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(event);
event.setAction(MotionEvent.ACTION_DOWN);
super.onTouchEvent(event);
event.setAction(MotionEvent.ACTION_UP);
returntrue;
}
return super.onTouchEvent(event);
}
Post a Comment for "Webview Getting Rid Of Double Tap Zoom."