2010-05-23 8 views
13

Ho creato un'app per iPhone bare bare con UIWebView (ridimensiona pagina su Adatta = YES, shouldAutorotateToInterfaceOrientation = YES) e caricato una pagina Web, ad es. https://stackoverflow.com/iPhone UIWebView larghezza non si adatta dopo l'operazione di zoom + UIInterfaceOrientation change

La rotazione del dispositivo mostra che UIWebView viene ridimensionato automaticamente per adattarsi alla larghezza. Buona.

errato: ingrandire la pagina e ridurla. Ora la rotazione del dispositivo mostra UIWebView in una larghezza strana in uno degli orientamenti (se si esegue lo zoom in orizzontale, la larghezza del ritratto è strana, viceversa). Questo comportamento è corretto solo quando navighi su un'altra pagina.

Correggere: caricare lo stesso URL in Safari mobile. Rotating works & la larghezza si adatta indipendentemente dall'esercizio di zoom.

Si tratta di un bug di UIWebView (probabilmente non)? O c'è qualcosa che deve essere fatto per rendere le cose "funzionano" come in Safari Mobile?

risposta

14

Ho trovato qualcosa che ha funzionato per me. Il problema è che quando uiwebview cambia il suo orientamento, i contenuti web vengono zoommati per adattarsi alla vista. Ma parametro zoomscale di ScrollView visualizzazione secondaria non viene aggiornato correttamente (e non vengono aggiornati minimumZoomScale né maximumZoomScale

allora abbiamo bisogno di farlo manualmente in willRotateToInterfaceOrientation:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 
    CGFloat ratioAspect = webview.bounds.size.width/webview.bounds.size.height; 
    switch (toInterfaceOrientation) { 
     case UIInterfaceOrientationPortraitUpsideDown: 
     case UIInterfaceOrientationPortrait: 
      // Going to Portrait mode 
      for (UIScrollView *scroll in [webview subviews]) { //we get the scrollview 
       // Make sure it really is a scroll view and reset the zoom scale. 
       if ([scroll respondsToSelector:@selector(setZoomScale:)]){ 
        scroll.minimumZoomScale = scroll.minimumZoomScale/ratioAspect; 
        scroll.maximumZoomScale = scroll.maximumZoomScale/ratioAspect; 
        [scroll setZoomScale:(scroll.zoomScale/ratioAspect) animated:YES]; 
       } 
      } 
      break; 
     default: 
      // Going to Landscape mode 
      for (UIScrollView *scroll in [webview subviews]) { //we get the scrollview 
       // Make sure it really is a scroll view and reset the zoom scale. 
       if ([scroll respondsToSelector:@selector(setZoomScale:)]){ 
        scroll.minimumZoomScale = scroll.minimumZoomScale *ratioAspect; 
        scroll.maximumZoomScale = scroll.maximumZoomScale *ratioAspect; 
        [scroll setZoomScale:(scroll.zoomScale*ratioAspect) animated:YES]; 
       } 
      } 
      break; 
    } 
} 

Spero che questo aiuti

+0

Grazie per la soluzione! Ho corretto il codice in modo che sia più facile per chiunque implementare nel proprio ViewController.m (il codice è anche duplicato in https://gist.github.com/834907) – choonkeat

+1

Fa ancora alcune cose strane con l'animazione, ma grazie;) È meglio di prima! Mi chiedo esattamente cosa fa Apple per soddisfare questo ... io penso che abbiano una sorta di classe non documentata che fornisce una soluzione. – PostCodeism

+0

Grazie - un po 'nervoso, ma migliore di prima. – daidai

1

Ho una soluzione a questo problema, ma devo dire che non ne sono un grande fan. Funziona alla grande, ma la soluzione causa effettivamente un altro problema. Ho una soluzione per il problema secondario, ma ci vuole un po 'di sforzo.

Basta tenere presente che dal momento che OS3.2 o iOS4 (non sono sicuro quale) subview diretto di UIWebView è ora UIScrollView invece di UIScroller, quindi possiamo fare molto di più con esso. Inoltre, poiché l'accesso alle sottoview di una vista non è un'azione privata, né l'utilizzo di una visualizzazione secondaria che viene castata come vista documentata, possiamo fare molto con UIWebView senza infrangere le regole.

In primo luogo abbiamo bisogno di ottenere l'UIScrollView dal UIWebView:

UIScrollView *sview = [[webView subviews] objectAtIndex:0]; 

Ora abbiamo bisogno di cambiare il delegato di questa ScrollView in modo che possiamo ignorare le chiamate ScrollView delegato (che potrebbe in realtà essere la causa di un bug secondaria a seguito di questa soluzione, che ho intenzione di condividere in un attimo):

sview.delegate = self; 

Ora, se si prova a questo punto, lo zoom è rotto. Abbiamo bisogno di implementare un metodo UIScrollViewDelegate per risolverlo. aggiungere:

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { 
    UIView *webBrowserView = [[scrollView subviews] objectAtIndex:10]; 
    return webBrowserView; 
} 

webBrowserView è in realtà un UIWebBrowserView, ma che non è una classe documentata, quindi stiamo solo andando a trattarlo come un UIView.

Ora esegui l'app, ingrandisci e rimpicciolisci la pagina web. Ruota e dovrebbe apparire correttamente.

Ciò provoca un bug piuttosto grande, che è forse peggiore dell'originale.

Se si ingrandisce e quindi si ruota, si perderà la capacità di scorrimento, ma la vista verrà ingrandita. Ecco la correzione Per completare il tutto.

In primo luogo, abbiamo bisogno di tenere traccia di alcuni numeri, e hanno una bandiera definito:

ho questi definito nel mio h di file:

BOOL updateZoomData; 
float zoomData; //this holds the scale at which we are zoomed in, scrollView.zoomScale 
CGPoint zoomOffset; //this holds the scrollView.contentOffset 
CGSize zoomContentSize; //this holds the scrollView.contentSize 

Si può pensare si può semplicemente prendere questi numeri da UIScrollView, ma quando ne hai bisogno, saranno cambiati, quindi abbiamo bisogno di loro memorizzati altrove.

Abbiamo bisogno di utilizzare un altro metodo delegato:

- (void)scrollViewDidZoom:(UIScrollView *)scrollView{ 
    if(updateZoomData){ 
     zoomData = scrollView.zoomScale; 
     zoomOffset = scrollView.contentOffset; 
     zoomContentSize = scrollView.contentSize; 
    } 
} 

Ora si ottiene in un pasticcio mi sento.

Abbiamo bisogno di tenere traccia di rotazione, quindi avrai bisogno di aggiungere questo alla vostra viewDidLoad, loadview, o qualsiasi metodo utilizzato per registrare le notifiche:

[[NSNotificationCenter defaultCenter] addObserver:self 
      selector:@selector(webViewOrientationChanged:) 
      name:UIDeviceOrientationDidChangeNotification 
      object:nil]; 

e creare questo metodo:

- (void)webViewOrientationChanged:(NSNotification *)notification{ 
    updateZoomData = NO; 
    [self performSelector:@selector(adjustWithZoomData) withObject:nil afterDelay:0.0]; 
} 

Così ora ogni volta che si ruota webViewOrientationChange verrà chiamato. La ragione per cui performSelector è in ritardo per 0,0 secondi è perché vogliamo chiamare adjustWithZoomData sul prossimo runloop. Se lo chiamate direttamente, adjustWithZoomData si regolerà per l'orientamento precedente.

Ecco il metodo adjustWithZoomData:

- (void)adjustWithZoomData{ 
    UIScrollView *sview = [[webView subviews] objectAtIndex:0]; 
    [sview setZoomScale:zoomData animated:YES]; 
    [sview setContentOffset:zoomOffset animated:YES]; 
    [sview setContentSize:zoomContentSize]; 
    updateZoomData = YES; 
} 

questo è tutto! Ora quando lo ruotate manterrà lo zoom e manterrà approssimativamente l'offset corretto. Se qualcuno vuole fare i conti su come ottenere l'esatto offset corretto, fallo!

+0

immagino Non ho menzionato, penso che questo sia un bug in primo luogo. – maxpower

+0

Ho anche notato che questo interrompe il doppio tocco per lo zoom indietro, sortof. – maxpower

+0

Ciao maxpower, c'è una documentazione sull'array views di un UIWebView? Se WebBrowserView è objectAtIdx: 10, quale voce dovrebbe essere pdf/jpg/png-documents caricata direttamente in UIWebView? – iFloh

4

ho provato! la soluzione da M Penades e questo sembra funzionare anche per me

L'unico problema che sto vivendo è che quando si esegue questo su un 3Gs la rotazione non è purtroppo molto liscia.

Sto quindi ora utilizzando un approccio diverso:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { 

[super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; 

CGFloat scale = browserWebView.contentScaleFactor; 
NSString *javaStuff = [NSString stringWithFormat:@"document.body.style.zoom = %f;", scale]; 
[browserWebView stringByEvaluatingJavaScriptFromString:javaStuff]; 

} 

migliori saluti,
Ralph

+0

Funziona Incredibilmente Grazie Ralph – Kamarshad

+0

funziona per l'inclinazione della UIWebView La risposta di 'M Penades' funziona perfettamente. un'altra cosa negativa in questa risposta è che ogni volta che il dispositivo ruota il javascript chiamerebbe questo porterà all'allarme di memoria. Quindi la risposta sopra è meglio. – Kamarshad

+0

Lo sto utilizzando in iOS8 all'interno di -viewWillTransitionToSize: withTransitionCoordinator: per forzare il ridimensionamento del componente interno di UIWebBrowserView dopo una rotazione. La risposta accettata non ha funzionato. – Jano

0

stavo cercando in questo me stesso e ho scoperto qualche informazione in più:

problemi quando modifica dello zoom:

  1. Safari spesso non risponde non è correttamente (se non del tutto) anche se il livello di zoom è cambiato.
  2. La modifica della larghezza consente di forzare un ridisegno.
  3. si potrebbe pensare che width = device-width in landscape utilizzi 1024 ma sembra che usi 768 (anche screen.width).

ad es. se la larghezza corrente è 1024 e si desidera ingrandire da 1 a 1,5 in orizzontale, è possibile:

  • cambiare combinazione di larghezza e zoom, ad es. larghezza a 2048 e lo zoom a 0,75
  • larghezza cambiamento a 1023 (brutto aliasing?)
  • larghezza cambiamento a dire 1023, poi la prossima linea di fondo a 1024 (doppio riverniciare, ma almeno è ridipinto finestra).
0

Quindi apparentemente non ho usato la soluzione di M Penades alla fine (e ho dimenticato di aggiornare questo post! Scusa).

Quello che ho fatto è stato ridimensionare l'intero documento (e cambiare la dimensione del font per mantenere le cose proporzionate). A quanto pare ha risolto il problema.

Tuttavia, il mio UIWebView è solo per caricare il mio HTML & CSS dal filesystem di iOS - se stai costruendo un browser web generico, questo trucco potrebbe non funzionare altrettanto bene.

ViewController.m

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 
    switch (toInterfaceOrientation) { 
     case UIInterfaceOrientationPortraitUpsideDown: 
     case UIInterfaceOrientationPortrait: 
      if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)) { 
       [webview stringByEvaluatingJavaScriptFromString:@"document.body.className = 'ppad'"]; 
      } else { 
       [webview stringByEvaluatingJavaScriptFromString:@"document.body.className = 'pphone'"]; 
      } 
      break; 
     default: 
      if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)) { 
       [webview stringByEvaluatingJavaScriptFromString:@"document.body.className = 'lpad'"]; 
      } else { 
       [webview stringByEvaluatingJavaScriptFromString:@"document.body.className = 'lphone'"]; 
      } 
      break; 
    } 
} 

E app.css

html>body.pphone { font-size:12px; width: 980px; } 
html>body.lphone { font-size:18px; width: 1470px; } 
html>body.ppad { font-size:12px; width: 768px; } 
html>body.lpad { font-size:15.99999996px; width: 1024px; } 

Gist a https://gist.github.com/d6589584944685909ae5

1

Sto inviando questo perché ho anche affrontato lo stesso problema ed eccomi qui a seguito della M Penades Approccio. La risposta di M Penades è valida solo per i casi in cui l'utente non inclina (pizzica) la visualizzazione Web, quindi ruota il dispositivo e ripete questo processo. La dimensione del contenuto di UiwebView viene ridotta gradualmente. quindi è stato il problema a rispondere M Penades. quindi ho risolto anche questo problema e il mio codice è il seguente.

1) Per questo ho impostato il Gesto di pizzicamento in modo che quando l'utente si inclina UIwebView può controllare la dimensione ridotta di UIwebView. // One Questo importa le UIGestureRecognizerDelegate protocollo in 'file h'

 //call below method in ViewDidLoad Method for setting the Pinch gesture 

- (void)setPinchgesture 
{ 
    UIPinchGestureRecognizer * pinchgesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(didPinchWebView:)]; 

    [pinchgesture setDelegate:self]; 

    [htmlWebView addGestureRecognizer:pinchgesture]; 
    [pinchgesture release]; 
    // here htmlWebView is WebView user zoomingIn/Out 

} 
    //Allow The allow simultaneous recognition 

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
    { 
    return YES; 
    } 

SI Tornando è garantito per consentire il riconoscimento simultaneo. NO ritorno non è garantita per evitare che il riconoscimento simultaneo, in qualità di delegato del l'altro gesto può restituire SI

-(void)didPinchWebView:(UIPinchGestureRecognizer*)gestsure 
    { 
    //check if the Scaled Fator is same is normal scaling factor the allow set Flag True. 
    if(gestsure.scale<=1.0) 
    { 
    isPinchOut = TRUE; 

    } 
    else// otherwise Set false 
    { 
    isPinchOut = FALSE; 
    } 
    NSLog(@"Hello Pinch %f",gestsure.scale); 
} 

Se Hase utente Pinch In/Out Il Web View in quel caso solo set che Zoom Factor. IN MODO che WebView possa regolare il suo contenuto come modificato.

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

    //Allow the Execution of below code when user has Skewed the UIWebView and Adjust the Content Size of UiwebView. 

    if(isPinchOut){ 
    CGFloat ratioAspect = htmlWebView.bounds.size.width/htmlWebView.bounds.size.height; 
    switch (toInterfaceOrientation) { 
    case UIInterfaceOrientationPortraitUpsideDown: 
    case UIInterfaceOrientationPortrait: 
     // Going to Portrait mode 
     for (UIScrollView *scroll in [htmlWebView subviews]) { //we get the scrollview 
      // Make sure it really is a scroll view and reset the zoom scale. 
      if ([scroll respondsToSelector:@selector(setZoomScale:)]){ 
       scroll.minimumZoomScale = scroll.minimumZoomScale/ratioAspect; 
       scroll.maximumZoomScale = scroll.maximumZoomScale/ratioAspect; 
       [scroll setZoomScale:(scroll.zoomScale/ratioAspect) animated:YES]; 
      } 
     } 
     break; 

    default: 
     // Going to Landscape mode 
     for (UIScrollView *scroll in [htmlWebView subviews]) { //we get the scrollview 
      // Make sure it really is a scroll view and reset the zoom scale. 
      if ([scroll respondsToSelector:@selector(setZoomScale:)]){ 
       scroll.minimumZoomScale = scroll.minimumZoomScale *ratioAspect; 
       scroll.maximumZoomScale = scroll.maximumZoomScale *ratioAspect; 
       [scroll setZoomScale:(scroll.zoomScale*ratioAspect) animated:YES]; 
      } 
     } 
     break; 
    } 
    } 

} 

Ciò funziona perfettamente anche per l'utente disallineare UIWebView.

4
- (UIScrollView *)findScrollViewInsideView:(UIView *)view 
{ 
    for(UIView *subview in view.subviews){ 
     if([subview isKindOfClass:[UIScrollView class]]){ 
      return (UIScrollView *)subview; 
     } 

     UIScrollView *foundScrollView = [self findScrollViewInsideView:subview]; 
     if (foundScrollView){ 
      return foundScrollView; 
     } 
    } 

    return nil; 
} 

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 
{ 
    switch (self.interfaceOrientation){ 
     case UIInterfaceOrientationLandscapeLeft: 
     case UIInterfaceOrientationLandscapeRight: 
     { 
      UIScrollView *webViewScrollView = ([self.webView respondsToSelector:@selector(scrollView)]) 
       ? self.webView.scrollView 
       : [self findScrollViewInsideView:self.webView]; 

      [webViewScrollView setZoomScale:1.01f animated:YES]; 
     } 
      break; 

     default: 
      break; 
    } 
} 

provare questo codice, cambia in modo insignificante il livello di zoom (1.01) per consentire UIWebView aumentare le dimensioni del contenuto in modalità paesaggio

findScrollViewInsideView: metodo aggiunto per supportare iOS4

Problemi correlati