web-dev-qa-db-fra.com

UIWebView ne redimensionne-t-il pas correctement lorsque l'orientation change?

J'ai ajouté une vue Web, un titleLabel et un coverflowView sur la vue d'un viewcontroller en tant que ses sous-vues, je veux qu'il change de taille lorsque l'orientation change. J'ai changé le cadre de la webview dans cette méthode:

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

son contenu a été redimensionné lorsque vous faites pivoter l'iPad d'orientationPaysage à orientationPortrait ou d'orientationPortrait à orientationPaysage si je lance l'application avec l'orientation portrait, mais il est si étrange que son contenu ne soit pas redimensionné lorsque je lance l'application avec l'orientation paysage ... Mais la NSLog montre que le cadre a changé. En ce qui concerne le titleLabel et le coverflowView, ils redimensionnent correctement. Je doute que ce soit à cause de CSS. J'ai utilisé CSS pour contrôler le style du contenu en fonction de la hauteur et de la largeur de la vue Web. Quelqu'un pourrait-il m'aider à trouver la raison? le code est ci-dessous:

- (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];

}
17
user424714

J'ai passé environ deux jours à essayer de dépister ce problème, car j'avais exactement le même problème. J'ai constaté que ma vue si elle commençait en mode Portrait serait correctement redimensionnée en mode Paysage. Toutefois, si je démarrais la vue en mode Paysage, la taille du portrait resterait la même.

Si votre vue couvre toute la largeur de l'appareil, il vous suffira d'ajouter la balise méta suivante.

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

Mais, dans mon cas, notre UIWebView est une taille non standard. Définir la fenêtre d'affichage sur device-width ne fait qu'aggraver la situation! J'ai pu tout faire fonctionner correctement en définissant la fenêtre de manière dynamique à l'aide de javascript. Cela devrait être fait lors de la mise en forme de sous-vues de la vue parent UIWebViews. Vous pouvez le faire dans willRotateToInterfaceOrientation, mais j'ai découvert que si vous le faites dans willRotate, certaines des tailles et interfaces risquent de ne pas être configurées correctement. Essayez-le d'abord et voyez comment fonctionne l'animation. 

Le code définit simplement la taille de la fenêtre d'affichage à la taille actuelle de l'image. Le code HTML que vous consultez doit avoir déjà une balise meta viewport (comme ci-dessus). Si vous ne pouvez pas modifier le code HTML, il existe d'autres moyens de l'ajouter via JavaScript. Le plus simple consiste simplement à ajouter la balise meta à la balise <head>. Ensuite, utilisez le code suivant APRES avoir correctement défini le cadre:

 // 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]];

Vous pouvez ajouter d'autres éléments de la fenêtre si vous ne souhaitez pas que l'utilisateur mette à l'échelle ou si vous souhaitez définir l'échelle maximale. Cela a fini par rendre la vue se comporter correctement pour notre UIWebView.

51

J'ai voté @ la réponse de christophercotton depuis que cela a fonctionné. Mais j’ai également constaté que je pouvais résoudre un problème similaire à celui-ci sans contrôler l’objet WebView. Sa solution m'a mis sur la bonne voie pour mon problème.

        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');
    }

Cela fonctionne sous iOS. Je ne l'ai pas essayé sous Android (pour ceux qui utilisent PhoneGap, par exemple).

1
Kevin Schroeder

J'ai un problème similaire et je ne trouve toujours pas de solution réelle à ce problème. J'appelle reload sur UIWebView pour contourner le problème, en disposant de la page des échelles.

[webView reload];
1
Khomsan

Donner une alerte si les autres ont le même problème.

La vue Web ne sera pas redimensionnée correctement car le code HTML est déjà rendu (je ne sais pas si cela est tout à fait vrai, cela pourrait bien être un bogue dans la vue Web elle-même), mais quoi qu'il en soit. J'ai créé une méthode qui redimensionne la largeur de corps Webview HTML:

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

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

Cela semble fonctionner très bien sur l'iphone, mais je devais le faire sur l'ipad

- (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"]];
}

Vous auriez pu aussi utiliser [self.webview reload] mais cela ferait une autre requête au serveur, et je pense que c'est mauvais ;-)

J'espère que ça aide!

1
Rasmus Styrk

J'ai essayé réponse de Christoper , traduisant son code OOC en Swift, mais ne fonctionnant pas. 

Enfin, je dois faire en sorte que la UIWebView recharge la page Web si la taille de l'écran a changé. Ce pourrait être un bidouillage, mais fonctionne quand même. Si cette réponse pouvait aider les développeurs de Swift plus ou moins. La fonction ci-dessous appartient à votre UIViewController.

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

Je viens d'avoir le même problème.

La solution qui a fonctionné pour moi a été de définir:

webView.scalesPageToFit = YES;
0
Raskal1979

Je rencontrais également le problème du dimensionnement incorrect du contenu UIWebView lors du passage de paysage à portrait.

Après avoir cherché pendant un moment, j'ai trouvé ma réponse:

"Une façon que j'ai trouvée de gérer cela consiste à recharger le contenu après le redimensionnement. Lorsque je dis" recharger ", je ne parle pas de la fonction de rechargement intégrée sur UIWebView, je parle de l'appel réel à loadHTMLString: baseURL: (ou quelle que soit la méthode que vous utilisez pour charger votre contenu initialement). " Message de Agent Gold sur le forum d'assistance Apple

0
Brian Gershon