2010-05-23 6 views
13

Я создал приложение для iPhone с голой костью с UIWebView (Scales Page to Fit = YES, shouldAutorotateToInterfaceOrientation = YES) и загрузил веб-страницу, например. https://stackoverflow.com/iPhone UIWebView ширина не подходит после операции масштабирования + UIInterfaceOrientation change

Вращение устройства показывает, что пользовательский интерфейс UIWebView автоматически изменяется в соответствии с шириной. Хорошо.

Неверно: Осмотрите страницу и уменьшите масштаб. Теперь вращение устройства показывает UIWebView в странной ширине в одной из ориентации (если и увеличить масштаб, ширина портрета странная, наоборот). Это поведение фиксируется только при переходе на другую страницу.

Исправить: Загрузить тот же URL-адрес в Mobile Safari. Вращающиеся работы & ширина подходит независимо от упражнения масштабирования.

Это ошибка UIWebView (возможно, нет)? Или есть что-то, что нужно сделать, чтобы «просто работать», как в Mobile Safari?

ответ

14

Я нашел что-то, что сработало для меня. Проблема заключается в том, что когда uiwebview меняет ориентацию, веб-контент зомбируется в соответствии с видовым экраном. Но zoomscale параметр Scrollview подвид не обновляются правильно (и не обновляется minimumZoomScale ни maximumZoomScale

Тогда мы должны сделать это вручную в 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; 
    } 
} 

Надеется, что это помогает

+0

Спасибо за решение! Я исправил код, так что для кого-то проще реализовать его в ViewController.m (код также дублируется на https://gist.github.com/834907) – choonkeat

+1

Он по-прежнему делает некоторые странные вещи с анимацией, но спасибо;) Это лучше, чем было раньше! Интересно, что именно делает Apple для этого ... я думаю, что у них есть какой-то недокументированный класс, который дает исправление. – PostCodeism

+0

Спасибо, бит, но лучше, чем раньше. – daidai

1

У меня есть решение этой проблемы, но я должен сказать, что я не большой поклонник этого. Он отлично работает, но решение на самом деле вызывает еще одну проблему. У меня есть исправление для вторичной проблемы, но это требует больших усилий.

Просто имейте в виду, что с OS3.2 или iOS4 (не уверен, какой) UUWebView прямое подчинение теперь UIScrollView вместо UIScroller, поэтому мы можем сделать с ним гораздо больше. Кроме того, поскольку доступ к облачным представлениям в представлении не является частным действием, ни один из них не использует подзаголовок, который отображается как документальное представление, мы можем многое сделать с UIWebView, не нарушая правил.

Сначала мы должны получить UIScrollView от UIWebView:

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

Теперь нам нужно изменить делегат этого Scrollview поэтому мы можем переопределить Scrollview делегировать вызовы (которые на самом деле может быть причиной вторичной ошибки в результате этого решения, которое я поделюсь в минуту):

sview.delegate = self; 

Теперь, если вы попробуете его в данный момент, масштабирование нарушается. Нам нужно реализовать метод UIScrollViewDelegate для его исправления. добавить:

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

webBrowserView фактически UIWebBrowserView, но это не документировано класс, так что мы просто будем рассматривать его как UIView.

Теперь запустите приложение, увеличьте масштаб, а затем уменьшите масштаб веб-страницы. Поверните, и он должен выглядеть правильно.

Это вызывает довольно большую ошибку, возможно, хуже оригинала.

Если вы увеличиваете масштаб и затем вращаетесь, вы потеряете способность прокрутки, но ваш вид будет увеличен. Вот исправление Чтобы завершить все это.

Во-первых, мы должны следить за несколько номеров, и иметь флаг, определенный:

Я это определено в моей час файла:

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 

Вы можете думать, что вы можете просто захватить эти номера из UIScrollView, но когда они вам понадобятся, они будут изменены, поэтому мы должны их хранить в другом месте.

Нам нужно использовать другой метод делегата:

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

Теперь он получает в беспорядок, я чувствую.

Мы должны отслеживать вращение, так что вам нужно, чтобы добавить это к вашему viewDidLoad, loadView, или любой другой метод используется для регистрации уведомлений:

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

и создать этот метод:

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

Итак, теперь, когда вы будете вращаться, будет вызываться webViewOrientationChange. Причина, по которой функция Selectlect задерживается на 0,0 секунды, заключается в том, что мы хотим вызвать adjustWithZoomData на следующей runloop. Если вы вызываете это напрямую, настройкаWithZoomData будет корректироваться для предыдущей ориентации.

Вот метод adjustWithZoomData:

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

Вот это! Теперь, когда вы вращаетесь, он будет поддерживать масштабирование и примерно поддерживать правильное смещение. Если кто-то хочет сделать математику о том, как получить точное правильное смещение, тогда идите!

+0

Я думаю, Я не упоминал, я думаю, что это ошибка в первую очередь. – maxpower

+0

Я также заметил, что это прерывает двойное нажатие для уменьшения, sortof. – maxpower

+0

Привет, Maxpower, есть ли документация в представлении-массиве UIWebView? Если WebBrowserView - objectAtIdx: 10, какая запись должна быть pdf/jpg/png-документами, загружаемыми непосредственно в UIWebView? – iFloh

4

Я пробовал! решение от M Penades и, похоже, работает и на меня.

Единственная проблема, с которой я столкнулся, заключается в том, что при запуске этого на 3Gs вращение, к сожалению, не очень плавное.

Я поэтому теперь использует другой подход:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { 

[super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; 

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

} 

С наилучшими пожеланиями,
Ральф

+0

Он работает Awesomely Спасибо Ralph – Kamarshad

+0

он действительно работает для Skew UIWebView Ответ 'M Penades' отлично работает. Другая неприятность в этом ответе заключается в том, что каждый раз, когда устройство вращает javascript, это вызовет это, как правило, приведет к предупреждению о памяти. Так что лучше ответить лучше. – Kamarshad

+0

Я использую это в iOS8 внутри -viewWillTransitionToSize: withTransitionCoordinator: принудительно изменить размер внутреннего компонента UIWebBrowserView после поворота. Принятый ответ не сработал. – Jano

0

Я смотрел на это сам и узнал больше информации:

вопросы, когда изменение масштаба:

  1. Safari часто не репрезентативно (если вообще), даже если уровень масштабирования изменился.
  2. Изменение ширины заставляет перекрашивать.
  3. Вы бы подумали, что ширина = ширина устройства в ландшафте будет использовать 1024, но, похоже, используется 768 (screen.width тоже).

, например. если текущая ширина равна 1024, и вы хотите увеличить с 1 до 1,5 в ландшафте, вы можете:

  • изменение комбинации ширины и масштаба, например. ширина до 2048 и увеличьте до 0,75
  • изменить ширину до 1023 (уродливое сглаживание?)
  • изменить ширину, чтобы сказать 1023, затем следующую строку назад к 1024 (двойная перекраска, но по крайней мере окно перекрашивается).
0

Так что, видимо, я не использовал решение M Penades в конце (и забыл обновить этот пост! Извините).

Что я сделал, это изменить размер всего документа (и изменить размер шрифта, чтобы сохранить пропорции). Это, видимо, решило проблему.

Однако мой UIWebView предназначен только для загрузки моего собственного HTML & CSS из файловой системы iOS - если вы создаете универсальный веб-браузер, этот трюк может и не работать.

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

И 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 на https://gist.github.com/d6589584944685909ae5

1

Я отправляю это, потому что я также столкнулась с той же проблемой, и вот я вслед за M Penades Подход. Ответ M Penades woks хорош только для случая, если пользователь не перекосит (pinch Out), Webview затем повернет устройство и повторит этот процесс. Затем содержимое Размер UiwebView постепенно уменьшается. так что вопрос был в M Penades Ответ. поэтому я исправил эту проблему и мой код выглядит следующим образом.

1) Для этого я установил жест Pinch, чтобы при пользовательском перекос UIwebView мог проверить масштабированный размер UIwebView. // Один Это импортируйте Протокол UIGestureRecognizerDelegate в «.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; 
    } 

Возвращение YES гарантированно позволяет одновременно признание. возвращение NO не гарантируются, чтобы предотвратить одновременное признание в качестве делегата другого жеста может вернуть YES

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

Если Hase Пользователь Pinch In/Out The Web View в этом случае просто установить, что трансфокации. ТАК, что WebView может отрегулировать его ContentSize при изменении Oreintaion.

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

} 

Это прекрасно работает для того, чтобы пользователь исказил 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; 
    } 
} 

Пробуйте этот код, он незначительно меняет уровень масштабирования (1.01), что позволяет увеличить размер UIWebView контента в ландшафтном режиме

findScrollViewInsideView: метод добавлена ​​поддержка iOS4