17

I have add a webview,a titleLabel and a coverflowView on a viewcontroller's view as its subviews, I want it to change size when the orientation change. I have change the webview's frame in this method:

 - (void)willRotateToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration: (NSTimeInterval)duration 

its content did resize when rotate iPad from orientationLandscape to orientationPortrait or from orientationPortrait to orientationLandscape if I start the application with portrait orientation, but it is so strange that its content dosen't resize when I start the application with landscape orientation...But the NSLog shows the frame has changed. As to the titleLabel and the coverflowView, they resize correctly. I doubt if it is because of css?I have use css to control the content's style according to the height and width of webview.Does anyone could help me to find the reason? the code is below:

- (void)willRotateToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration: (NSTimeInterval)duration {
double i = 0;
NSInteger  width=self.view.frame.size.width;
NSInteger  height=self.view.frame.size.height;
NSLog(@"view :%@",[self.view description]);
switch (toInterfaceOrientation){
    case UIInterfaceOrientationPortrait:
    {    
        NSLog(@"rotate to Portrait");
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
            self.docView.frame=CGRectMake(0, 50, width+20, height-70);
            self.toolbar.frame=CGRectMake(0, 0,height , 50);
            for (UIView * view in [toolbar subviews]) {
                if ([view isKindOfClass:[UIButton class]] && view.tag==kBackButtonTag){
                    view.frame=CGRectMake(width-60, 6, 50, 36);

                }else if([view isKindOfClass:[UIButton class]] && view.tag==kReloadButtonTag){
                    view.frame=CGRectMake(width-160, 6, 80,36 );
                }
            }
            [coverflow setFrame:CGRectMake(0, 0 , width+20, height/2-50)];
            [titleLabel setFrame:CGRectMake(width/2-40,height/2-100, 100, 20)];
            if ([[[UIDevice currentDevice]model]isEqualToString:@"iPad"]) {
                self.viewer.frame=CGRectMake(0, 0, 768, 1004);
            }else{
                self.viewer.frame=CGRectMake(0, 0, 320, 480);
            }
        }
        i=0;
    }break;
    case UIInterfaceOrientationPortraitUpsideDown:
    {
        NSLog(@"rotate to PortraitUpsideDown");
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
            self.docView.frame=CGRectMake(0, 50, width+20, height-70);
            self.toolbar.frame=CGRectMake(0, 0,height , 50);
            for (UIView * view in [toolbar subviews]) {
                if ([view isKindOfClass:[UIButton class]] && view.tag==kBackButtonTag)  {
                    view.frame=CGRectMake(width-60, 6, 50, 36);

                }else if([view isKindOfClass:[UIButton class]] && view.tag==kReloadButtonTag){
                    view.frame=CGRectMake(width-160, 6, 80,36 );
                }
            }

            [coverflow setFrame:CGRectMake(0, 0 , width+20, height/2-50)];
            [titleLabel setFrame:CGRectMake(width/2-40,height/2-100, 100, 20)];
            if ([[[UIDevice currentDevice]model]isEqualToString:@"iPad"]) {
                self.viewer.frame=CGRectMake(0, 0, 768, 1004);
            }else{
                self.viewer.frame=CGRectMake(0, 0, 320, 480);
            }

        }

        i=180;
    }   break;
    case UIInterfaceOrientationLandscapeLeft:{

        NSLog(@"rotate to LandscapeLeft");
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
       //     self.coverflow.frame=CGRectMake(0, 0, height+20, width-20);
            self.docView.frame=CGRectMake(0, 50, height+20, width-70);
            self.toolbar.frame=CGRectMake(0, 0,height+20 , 50);
            for (UIView * view in [toolbar subviews]) {
                if ([view isKindOfClass:[UIButton class]] && view.tag==kBackButtonTag)  {
                    view.frame=CGRectMake(height-60, 6, 50, 36);
                    NSLog(@"button %@",[view description]);
                }else if([view isKindOfClass:[UIButton class]] && view.tag==kReloadButtonTag){
                    view.frame=CGRectMake(height-160, 6, 80,36 );
                }
            }
            [coverflow setFrame:CGRectMake(0, 0 , height+20, width/2-50)];
            [titleLabel setFrame:CGRectMake(height/2-40,width/2-80, 100, 20)];
            if ([[[UIDevice currentDevice]model]isEqualToString:@"iPad"]) {
                self.viewer.frame=CGRectMake(0, 0, 1024, 748);
            }else{
                self.viewer.frame=CGRectMake(0, 0, 480, 320);
            }
        }

        i = 90;
    }break;
    case UIInterfaceOrientationLandscapeRight:{
        NSLog(@"rotate to LandscapeRight");
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
        //    self.coverflow.frame=CGRectMake(0, 0, height+20, width-20);
            self.docView.frame=CGRectMake(0, 50, height+20, width-70);
            self.toolbar.frame=CGRectMake(0, 0,height+20 , 50);
            for (UIView * view in [toolbar subviews]) {
                if ([view isKindOfClass:[UIButton class]] && view.tag==kBackButtonTag)  {
                    view.frame=CGRectMake(height-60, 6, 50, 36);
                }
                else if([view isKindOfClass:[UIButton class]] && view.tag==kReloadButtonTag){
                    view.frame=CGRectMake(height-160, 6, 80,36 );
                }
            }
            [coverflow setFrame:CGRectMake(0, 0 , height+20, width/2-50)];
            [titleLabel setFrame:CGRectMake(height/2-40,width/2-80, 100, 20)];
            if ([[[UIDevice currentDevice]model]isEqualToString:@"iPad"]) {
                self.viewer.frame=CGRectMake(0, 0, 1024, 748);
            }else{
                self.viewer.frame=CGRectMake(0, 0, 480, 320);
            }
        }

        i = -90;
    }break;
}

//[webViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
// [self.view setNeedsDisplay];
//   NSLog(@"coverflowView :%@",[self.coverflow description]);
   NSLog(@"webview :%@",[viewer description]);
    [viewer stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__defineGetter__('orientation',function(){return %f;});",i]];
    [viewer stringByEvaluatingJavaScriptFromString:@"var e = document.createEvent('Events'); e.initEvent('orientationchange', true, false); document.dispatchEvent(e); "];    
}




- (void)viewDidLoad {
self.view.clipsToBounds=YES;
self.view.autoresizesSubviews=YES;
// self.view.autoresizingMask=UIViewAutoresizingNone;

viewer=[[UIWebView alloc]initWithFrame:self.view.bounds];

[self.view addSubview:viewer];
 viewer.delegate=self;
 viewer.scalesPageToFit=NO;
 viewer.autoresizesSubviews=NO;
 viewer.autoresizingMask=UIViewAutoresizingNone;
viewer.dataDetectorTypes=0;
// viewer.autoresizingMask=UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;
NSLog(@"webView :%@",[viewer description]);
//  [viewer setFrame:CGRectMake(0, self.view.bounds.size.height/2 , self.view.bounds.size.width, self.view.bounds.size.height/2)];
//  [viewer setBounds:CGRectMake(0, self.view.bounds.size.height/2 , self.view.bounds.size.width, self.view.bounds.size.height/2)];

UIScrollView *scroller=[viewer.subviews objectAtIndex: 0];
if (scroller) {
    scroller.alwaysBounceVertical=NO;
    scroller.bounces=NO;
    scroller.scrollEnabled=NO;   
}

[self viewHomePage];
//[self createCoverFlowView];
[self createPopView];
//[self setHomeButtonPosition]; 
//[self setSettingButtonPosition];

#if __IPHONE_OS_VERSION_MIN_REQUIRED > 30000
UILongPressGestureRecognizer* longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
[self.view addGestureRecognizer:longPress];
longPress.minimumPressDuration=2.0;
longPress.delegate = self;
longPress.cancelsTouchesInView = NO;
longPress.allowableMovement=20;
[longPress release];  

UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleTap];
singleTap.delegate = self;
singleTap.cancelsTouchesInView = NO;
[singleTap release];  
#endif
//[viewer setOpaque:YES];      //透明
[super viewDidLoad];

}
Community
  • 1
  • 1
user424714
  • 181
  • 1
  • 1
  • 4
  • I've got this exact same issue. If the app starts in Portrait mode. the UIWebView Correctly adjusts the size and my CSS shows it has changed. If I start it in Landscape mode, it doesn't change anymore. – christophercotton May 21 '11 at 20:23

7 Answers7

52

I spent about two days trying to track this problem down, as I was having the exact same issue. I found that my view if it started off in Portrait mode would correctly resize to Landscape. But, if I started the view in Landscape mode, it would keep the same size in Portrait.

If your view is the entire width of the device, just adding the following meta tag will work.

<meta name="viewport" content="width=device-width" />

But, in my case, our UIWebView is a nonstandard size. Setting the viewport to device-width just makes it worse! I was able to have everything work out correctly by setting the viewport dynamically using javascript. This should be done during the UIWebViews parent view's layoutSubviews. You can do it in the willRotateToInterfaceOrientation, but I found out if you do in willRotate some of the sizes and interfaces might not be setup correctly. Try it there first and see how the animation works.

The code just sets the viewport size to the current frame size. The HTML you are viewing must have a meta viewport tag already (as above). If you can't edit the HTML, there are other ways of adding it via javascript. The easiest is to just add in the meta tag into the <head> tag. Then use the following code, AFTER you have set the frame correctly:

 // assuming your self.viewer is a UIWebView
[self.viewer stringByEvaluatingJavaScriptFromString:
     [NSString stringWithFormat:
     @"document.querySelector('meta[name=viewport]').setAttribute('content', 'width=%d;', false); ",
      (int)self.viewer.frame.size.width]];

You can add in other viewport items if you don't want the user to scale, or you want to set the max scale. This ended up making the view behave correctly for our UIWebView.

christophercotton
  • 5,829
  • 2
  • 34
  • 49
  • Works. I have a subclass of UIWebView and was able to put this fix inside setFrame:. – TomSwift Aug 01 '11 at 14:49
  • @TomSwift setFrame did not work for me, I used layoutSubviews – aryaxt Mar 07 '12 at 16:06
  • @aryaxt That is where I do in our shipping app, inside LayoutSubviews. – christophercotton Mar 07 '12 at 17:04
  • 1
    Answer to a similar SO question worked on both iPad and iPhone with a master-detail application. The solution above failed on iPad. See: http://stackoverflow.com/a/3634978/54426 – Rich Apodaca Apr 13 '12 at 22:02
  • This solution worked perfectly on iPad for me, but the one given by Rich Apodaca seems event better to me as there is no need to overload the -layoutSubviews method. Thank you all ! – Thomas Desert May 21 '12 at 14:44
1

I upvoted @christophercotton's response since it worked. But I also found I could fix a problem similar to this without controlling the webview object. His solution put me on the right track for my problem.

        var el = $('meta[name=viewport]');
    if (window.orientation == 90 || window.orientation == -90) {
        el.attr('content', 'width=device-height');
    } else {
        el.attr('content', 'width=device-width');
    }

This works in iOS. Have not tried it in android (for those using the likes of PhoneGap).

Kevin Schroeder
  • 1,296
  • 11
  • 23
1

I have a similar issue and still cannot find real solution to this. I call reload on UIWebView to work around the issue, by having the scales page to fit on.

[webView reload];
Khomsan
  • 543
  • 5
  • 5
  • doesn't work for www.msn.com [self.webViewMain setFrame:CGRectMake(0.0, 44.0, 1024.0, 724.0)]; [self.webViewMain stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat: @"document.querySelector('meta[name=viewport]').setAttribute('content', 'width=%d;', false); ", (int)self.webViewMain.frame.size.width]]; – Izac Mac Jun 06 '12 at 09:53
1

Just giving a headsup if others have same problem.

The webview wont resize properly because the HTML is already rendered (iam not sure if this is completely true, might just be a bug in the webview itselfs), but anyway. I made a method that resizes the webview html body width:

- (void) resizeHtml
{
     NSString *jsString = [[NSString alloc] initWithFormat:@"document.getElementsByTagName('html')[0].style.width= '%dpx'", (int) _frame.size.width];

    [self.webView stringByEvaluatingJavaScriptFromString:jsString];
    [jsString release];
}

This seems to work just fine on the iphone, but on the ipad i had to do this

- (void) reloadHtml
{
    NSString *html = [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.outerHTML"];

    if(html == nil || [html isEqualToString:@""] || [html length] < 100)
        [self.webView reload];

    [self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"some base url"]];
}

You could also have used [self.webview reload] but that would make another request to the server, and i think that is bad ;-)

I hope this helps!

Rasmus Styrk
  • 1,296
  • 2
  • 20
  • 36
  • 1
    Not sure that is the best method, since you are pulling your entire document over via a string and then reloading it. At least people should know that you are causing the entire page to reload. – christophercotton Jan 03 '12 at 05:47
  • that is true, but i can't seem to find a better solution when auto zoom is off - and i have tried doing this with fairly large documents with no problems – Rasmus Styrk Jan 03 '12 at 07:03
0

I just had the same issue.

The solution that worked for me was to set:

webView.scalesPageToFit = YES;
0

I tried Christoper's answer, translating his OOC code to Swift, but not working.

Finally, I have to make the UIWebView reload the webpage if the screen size changed. It might be a hack, but works anyway. Wish this answer could help Swift developers more or less. The function below belongs to your UIViewController.

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    coordinator.animateAlongsideTransition(nil, completion: {context in
        self.webView.reload()            
    })
}
Community
  • 1
  • 1
T.Liu
  • 492
  • 1
  • 5
  • 16
0

I was also experiencing the problem of the UIWebView contents not sizing properly when switching from landscape to portrait.

After hunting around for awhile, I found my answer:

"One way I've found to handle this is to reload the content after the resize. When I say "reload," I don't mean the built-in reload function on UIWebView, I mean the actual call to loadHTMLString: baseURL: (or whichever method you use to load your content initially)." Agent Gold's post on Apple Support forum

Brian Gershon
  • 111
  • 1
  • 1
  • 1
    Be careful when posting copy and paste boilerplate/verbatim answers to multiple questions, these tend to be flagged as "spammy" by the community. – Kev Jul 23 '11 at 12:26
  • Thanks Kev for the note. I did purposely post in both places to save the next person some time finding the answer depending on which question they came upon first. The answer seemed appropriate for both. – Brian Gershon Jul 29 '11 at 22:07
  • 1
    also, reloading the content is a bad solution for many folks. Especially if you already have javascript in there, and they user has done something to the page. Like display a different set of items, or started typing in something. By reloading, you will cause all of that to be removed. – christophercotton Jun 08 '12 at 20:02