1

I am showing a webpage in an Android WebView. The page needs to be scaled to fit the available width of the WebView.

HTML (width 550 is just an example, that could change):

<html> 
<head> 
<meta name="viewport" content="width=550">
...

Java:

mWebView = (WebView)findViewById(R.id.webView);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setHorizontalScrollBarEnabled(false);
mWebView.setVerticalScrollBarEnabled(false);
mWebView.requestFocus(View.FOCUS_DOWN);
mWebView.getSettings().setLoadWithOverviewMode(true); // required for scaling
mWebView.getSettings().setUseWideViewPort(true); // required for scaling
mWebView.loadUrl(someUrl);

This works fine, except one problem: double-tab triggers a switch between overview mode and default scale.
Is there any way to disable this functionality?

Btw: I cannot calculate the scale in the code, because the loaded pages might have different sizes, which I do not know beforehand. I also already checked the source code of WebView, but do not see anything, that I could override or change.

joce
  • 9,624
  • 19
  • 56
  • 74
SimonSays
  • 10,867
  • 7
  • 44
  • 59

3 Answers3

1

You could write your own WebView implementation implemting OnGestureListener:

public class MyWebView extends WebView implements OnGestureListener

Inside declare a GestureDetector:

  private GestureDetector             gestureDetector;

Implement a initWebView() method and call it in the constructor like this:

// Best you do this for every WebViewConstructor:
  public AppWebView(Context context) {
  super(context);
  initWebView(); }

private void initWebView(){
   gestureDetector = new GestureDetector(getContext(), this);
   // Do any other customizations for your webview if you like. 
}

Now implement the methods from OnGestureListener and return true on double tap events:

  public boolean onSingleTapConfirmed(MotionEvent e) {
    return false; //Nothing
  }

  public boolean onDoubleTap(MotionEvent e) {
    return true; //Nothing
  }

  public boolean onDoubleTapEvent(MotionEvent e) {
    return true; //Nothing
  }

  public boolean onDown(MotionEvent e) {
    return false; //Nothing
  }

  public void onShowPress(MotionEvent e) {
    //Nothing
  }

  public boolean onSingleTapUp(MotionEvent e) {
    return false; //Nothing
  }

  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    return false; //Nothing
  }

  public void onLongPress(MotionEvent e) {
    //Nothing
  }

  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    return false; //Nothing
  }

Finally Override OnTouchEvent of your webview and let it pass through events to the gesture detector like this:

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (gestureDetector.onTouchEvent(event)) return true;
    return super.onTouchEvent(event);
  }

This works pretty good generally but there is 1 basic flaw to this solution: Some Events that are not identified as DoubleTap events could cause the Zoom of your webview.

I´m still working on a solution for that and will post my progress here: WebView getting rid of double tap zoom.

Community
  • 1
  • 1
Ostkontentitan
  • 6,930
  • 5
  • 53
  • 71
  • Thx, that looks promising. I'll accept it as answer without testing it out. I've made a hack where I completely disable the zooming, pass the WebView with to the HTML and fit the content from within the javascript. Not very nice, but it works. – SimonSays Sep 10 '12 at 18:07
0

in General, changing a known API is not good practice. you should probably find a different way to do that, maybe longClick.

anyway, look at this similar question.

Community
  • 1
  • 1
thepoosh
  • 12,497
  • 15
  • 73
  • 132
0

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.

<script type="application/javascript" src="fastclick.js"></script>

    <script language="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(new OnDoubleTapListener() {

    @Override
    public boolean onSingleTapConfirmed( MotionEvent e ) {
        return false;
    }

    @Override
    public boolean onDoubleTapEvent( MotionEvent e ) {

        return true;
    }

    @Override
    public boolean onDoubleTap( MotionEvent e ) {

        return true;
    }
});

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 events
    if (actionMask == MotionEvent.ACTION_MOVE) {

        return super.onTouchEvent(event);
    }

    // cancel detected double taps
    if (gestureDetector.onTouchEvent(event)) {
        event.setAction(MotionEvent.ACTION_CANCEL);
        super.onTouchEvent(event);
        return true;
    }

    // if you want to ignore multi touch events/taps
    if (pointId != 0) {

        System.out.println("KEY multiple points detected");
        return true;
    }

    // use single taps
    if (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);
        return true;
    }

return super.onTouchEvent(event);
}
bapho
  • 858
  • 8
  • 13