Mister B
Mister B

Reputation: 123

Proper scaling of a web site on Android devices via WebView

My application is a simple WebView "wrapper" that displays a web page in a fixed landscape orientation, the page has a centered div that is 760px wide and 415px high and this should be displayed scaled on all devices so it (roughly) fits the screen, the user cannot change the scaling... I've almost got everything working apart from the scaling.

I have the following viewport meta tag on the page :

<meta name="viewport" content="width=device-width, target-densityDpi=device-dpi, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>

The manifest for the WebView wrapper .apk I've created is as follows:

<supports-screens android:smallScreens="true"
android:normalScreens="true" android:largeScreens="true"
android:anyDensity="true" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name="{my name}"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

I should mention that originally the .apk target was Android 2.2 and I've recently changed up to 2.3.1 and added another line to the manifest but that's made no difference to anything :

android:xlargeScreens="true"

I added the following in to the .java code :

webview.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
webview.setScrollbarFadingEnabled(false);
webview.getSettings().setSupportZoom(false);
webview.getSettings().setBuiltInZoomControls(false);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

For the purpose of this question just assume that the only content on the entire site is the following <div>:

<div style="margin: auto; position:relative; align:center; top:0px; width:760px; height:415px; background-color:#000000">

My problem is I can't to come up with a "one-size-fits-all" scaling solution across all Android devices, everything else I've tasked myself with delivering works fine.

I've tried this on three different devices, one tablet and two phones, and there is a large gap on the left, right and bottom of the <div> layer. It looks like the 760px width has about another 50px gap on either side and the same underneath on each of the devices, all I want to do is scale that up so it roughly fills the screen on all of the devices.

My phone says it's got a window.innerWidth of 854 with a window.devicePixelRatio of 1.5 and if I change the initial and maximum scale to 1.12 the <div> layer fits just about perfectly on my device. The table says it's got a window.innerWidth of 980 with a window.devicePixelRatio of 1.0 and seems to like a scale of around 1.27. I don't know the details of the third device but using 1.1 seem to do the trick on that.

Of course changing the initial scaling isn't a solution and even attempting it would be a complete nightmare so, fingers crossed, can anyone tell me the blindingly obvious thing that I'm missing that'll make this work? Or am I just asking the impossible to automatically scale the view to a fixed size <div>?

Upvotes: 4

Views: 7221

Answers (1)

Mister B
Mister B

Reputation: 123

Right... On the way home I was stuck in a jam and had a jolly good think, I came to the conclusion that I was dramatically over-thinking this problem.

This is rough but it does the job, I removed the meta tag from the site and added this to the application :

// Set up up the scaling value
float scaling = 100;
int display_width;
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
display_width = dm.widthPixels;
scaling = (((float)display_width/760)*100); // 760 here is my container div width
scaling = (int) Math.floor(scaling); 
// Set up the webview and apply the scale value
webview = (WebView) findViewById(R.id.webview);
webview.setInitialScale((int)scaling);  

That works quite well but I have encountered two issues since I made this post.

The first is that by removing the meta tag I seem to have removed my limitation on the maximum/minimum scale, this means that clicking on any <INPUT> element which displays the Android keyboard will result in a change in the scaling. Luckily, adding this line to the code solves this issue so far :

webview.getSettings().setDefaultZoom(ZoomDensity.FAR);

The second I don't have a workable solution for and is that some devices, such as the Archos101 tablet, have software buttons instead of hardware buttons. The scaling code here will scale to the device width and that means the site goes underneath the software buttons... Currently thinking about implementing a solution based on READ_PHONE_STATE or optionally adding the ability to quit the application without hardware buttons and adding this to the manifest :

<uses-permission android:name="archos.permission.FULLSCREEN.FULL" />

Hopefully someone else will find this and save themselves some time.

Upvotes: 7

Related Questions