Skip to content


Changing the range of the zoom factor for UIWebView objects

When using a UIWebView to display a web page, you have probably noticed that the maximum zoom factor is very limited. In mobile Safari you can zoom in much farther than in your own App. This blog post will explain, how you can increase the maximum zoom factor.

The UIWebView class does not have any methods to set the zoom factor. But this can be done with certain instructions within the HTML code. The META tag can be used to configure the viewport, which includes the initial, the minimum and the maximum zoom factor.

The META tag can look like this:

<meta name="viewport" content="minimum-scale=0.6; maximum-scale=5;  initial-scale=1; user-scalable=yes; width=640">

The following viewport parameters can be used:

  • minimum-scale:
    This is the minimum zoom factor that is allowed. The default value is 0.25, the range is from >0 to 10.

  • maximum-scale:
    This is the maximum zoom factor that is allowed. The default value is 1.6, the range is from >0 to 10

  • initial-scale:
    This is the zoom factor that is used when the web page is loaded before the user zooms in or out. The default value is calculated so that the web page fits in the visible area. But the final range will be also within the range from the minimum to the maximum factor.

  • user-scalable
    This parameter can be used to allow or disallow that the user can zoom the web page.

  • width:
    This parameter defines the width for the viewport. By default the width is set to 980 px on an iPhone. The possible range for this value is from 200 to 10000. The special value “device-width” represents the width of the device (which is 320 on an iPhone and 768 on an iPad). Please note that the device width is not the same as the width of the user interface. The device width is always represented by the width of the device in portrait orientation (the “natural” orientation of the device). If we want to increase the maximum zoom factor of a web page (the default factor is 1.6), we only need to add a META tag in the HTML code of the page, which defines the maximum zoom factor. If you can change the original HTML code, you can simply add the META tag and you’re done. If your App loads web pages from the internet and you can’t change the original HTML code, you have to write JavaScript code which creates a META tag and adds it to the HTML code of the web page. If you’ve read my other blog posts, you’ll already know how this works.
  • height:
    This parameter defines the height for the viewport. Usually this is calculated based on the width.

The JavaScript code could look like this:

File: IncreaseZoomFactor.js:

function increaseMaxZoomFactor() {
  var element = document.createElement('meta');
  element.name = "viewport";
  element.content = "maximum-scale=10";
  var head = document.getElementsByTagName('head')[0];
  head.appendChild(element);
}

Within the webViewDidFinishLoad: delegate method of the UIWebView object you can then inject this JavaScript code into the web page and call the function to increase the maximum zoom factor:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
  NSString *path = [[NSBundle mainBundle] pathForResource:@"IncreaseZoomFactor" ofType:@"js"];
  NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
  [webView stringByEvaluatingJavaScriptFromString:jsCode];

  [webView stringByEvaluatingJavaScriptFromString:@"increaseMaxZoomFactor()"];
}

When dealing with web pages from the web, you have to be careful because many of these web pages do already use META tags to change the zoom factor or other viewport parameters. If you add the new META tag as described above, you’ll overwrite the maximum-scale parameter and the other parameters remain unchanged. Which means, if the same parameter is defined in multiple META tags, the last one wins. Most of the time this is fine, but in some cases this can have some side effects.

For example if the web page defines some parameters which would result in an initial zoom factor of 4, but because the page does not define the maximum-scale parameter, the default value of 1.6 would also limit the initial zoom factor to 1.6. If you now increase the maximum-scale parameter, the initial zoom factor will be increased as well because it is no longer limited by the maximum zoom factor. If this can be critical for your App, you need to check for the existing parameters and based on their values you may need to define some other parameters as well (for example you may explicitly add the initial-scale parameter with a value of 1.6 to prevent that the maximum zoom factor initially zooms the page much more than it would do without your modification).

Posted in iPhone & iPod Touch, Programming.

Tagged with , , , , .


14 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Thomas says

    Useful information, well explained. Thank you!

  2. denizen says

    Great post. I’m writing a little iOS browser as a side project, and I need a little advice. (this probably isn’t the right area of the site to ask it, but I couldn’t find your email)
    Anyway, I’m implementing multiple tabs, each comprising one UIWebView. When I receive a memory warning, I release all non-foreground tabs. Problem is, even when I’ve released them, quite a bit of memory stays behind. I’ve verified they’re being released in instruments, and I regain a bit of memory, but not nearly all of it. What can I do about this? I’m thinking this is an issue with a cache not being released; Instruments says the leftover memory is CFData that the webview created internally. What can I do about this? Os there something I can do to manually flush the cache?

  3. Alexander Alexander says

    @denizen
    You can’t do anything here. The iOS seems to use a shared cache for all UIWebView objects of an App and therefore when you release one UIWebView object, this hasn’t much impact on the memory usage because of this shared caches. But the iOS should nevertheless release (parts of) the cache when your App can’t free enough memory otherwise.

  4. denizen says

    Thanks.
    The problem is, I’m surpassing the memory limit before iOS frees the cache, so the app’s being killed due to memory usage. I’m testing on a relatively low-RAM device (iPod Touch 2G, running iOS4), so it might just be an issue with iOS. I’ll try to get ahold of a bigger device and see if the problem persists.

  5. tiantian says

    Sorry for asking here, because I don’t know your e-mail. It’s about the web page saving feature. I wander how you save page as webarchive file? It seems Webarchive is a class in Mac os API, not in IOS . Did you use private API to do that?

  6. Alexander Alexander says

    @tiantian
    Technically the webarchive file format is equal to the standard binary property list file format. So the webarchives can be created using the standard NSPropertyListSerialization class.

  7. tiantian says

    Thanks a lot for your replay, but how to get the binary property list of a web page? I can get all the data response from a url, but the data’s format is not a binary property list type . Is there a way to convent that data to a binary property list type?

  8. Alexander Alexander says

    @tiantian
    If you open an existing webarchive in the properties list editor, you’ll see how this works. Basically the webarchive is a structure of NSArrays, NSDictionaries which represents the page structure with all its files. And all the files data is stored as NSData objects. So you just need to store the raw data you’ve got from the NSURLResponses together with the meta data (MIME type, URL) in the correct array/dictionary structure. And to save this structure as binary property list, you can use the NSPropertyListSerialization class.

  9. tiantian says

    Thanks again. I’ve successed save data into webarchive file. But the way I get all the data is too complicate. I parse all image and js element in the main html document and start a NSURLConnection for each of them. Do you have a better way to get all the data from a url including image and js? BTW, I found UIWebview never cache any data automatically, did you use any cache mechanism for save page? I see the page can be immediately saved after I tab that button even I turn wifi off.

  10. Alexander Alexander says

    @tiantian
    Basically, parsing the main HTML file for other files is what you need to do.

    It is true that the iOS doesn’t use a “disk” cache, but at least the NSURLCache object is called, which is prepared to maintain a disk cache, but just doesn’t cache any files on disk.
    But iCab overwrites the NSURLCache to implement its own cache which can save files on disk (this is also used for the Offline mode). So iCab usually doesn’t need to download files again.

  11. Eric says

    Hi Alexander
    I have met a trouble about UIWebView ,In the mobile/safari When i zoom the contentView it became larger or smaller,but the navigationbar have no effect like this .It does not change the size by the contentView zoom or not. I want to use UIWebView to do like this I found that when i scorlled the contentView the safari’s navigationbar scolling with the contentView, and I have dumped the UIWeView’ hierarchy ,only one scrollView in UIWebView,I don’t know how to do it. Any help will appricate.

  12. Alexander Alexander says

    @Eric
    The Navigation toolbar is not sitting within the content area of the UIWebView and therefore does not zoom with the content area. In order to get a scrolling navigation toolbar like in Safari, you can get a reference to the internal UIScrollView of the UIWebView (requires iOS 5) and then use the scrollview properties and the scrollview delegate methods to move the navigation together with the content when it is scrolled. You can also set the content offset or insets for the scrollview to initially move the content down in order to make room for the navigation toolbar, so the navigation toolbar can be placed on top of the UIWebView without overlapping the content area of the UIWebView when it is scrolled to the top.
    When scrolling down, the UIScrollView delegates will be called and will tell you how much the content area is scrolled. And so you know how much you need to move the navigation toolbar out of view.

  13. Eric says

    My app is running ios4.x and higher,I have see someone have maked it true on ios 4.x.But i don’t know how can do that. If the UIWebView have two scrollViews? After contentView zoom it can move left or right and navigationBar can down or up.

  14. Alexander Alexander says

    @Eric
    Putting a UIWebView into a UIScrollView is highly discouraged by Apple for good reasons. While it seems to work at first glance, there will be conflicts with the gestures.

    Of course you can get the reference to the scrollview of the WebView under iOS 4 as well, but this would mean that you have to make certain assumptions about the internal view hierarchy of UIWebView (you assume that there’s a UIScrollView internally), which is strictly speaking using “private” API. You could do this with only using the public API though, by checking all subviews of UIWebView and look for the scrollview. But because Apple has not documented the internals of UIWebView, be prepared that you might not always find want you’re looking for. Use the new iOS 5 API when available to get the reference to the scrollview. This is a safe way to get access to the scroll view.



Some HTML is OK

or, reply to this post via trackback.