【问题标题】:iPhone UIWebView width does not fit after zooming operation + UIInterfaceOrientation change缩放操作 + UIInterfaceOrientation 更改后 iPhone UIWebView 宽度不适合
【发布时间】:2011-02-22 20:34:00
【问题描述】:

我用 UIWebView 创建了一个简单的 iPhone 应用程序(缩放页面以适应 = YES,shouldAutorotateToInterfaceOrientation = YES)并加载了一个网页,例如https://stackoverflow.com/

旋转设备显示 UIWebView 自动调整大小以适应宽度。很好。

不正确:放大页面并缩小页面。现在旋转设备在其中一个方向上以奇怪的宽度显示 UIWebView(如果你放大横向,纵向宽度很奇怪,反之亦然)。仅当您导航到另一个页面时,此行为才会得到修复。

正确:在 Mobile Safari 中加载相同的 URL。无论缩放练习如何,旋转都有效且宽度适合。

这是一个 UIWebView 错误吗(可能不是)?或者是否需要做一些事情才能让事情像在 Mobile Safari 中一样“正常工作”?

【问题讨论】:

    标签: iphone uiwebview width zooming autoresize


    【解决方案1】:

    我有解决这个问题的办法,但我得说我不是它的忠实粉丝。它工作得很好,但该解决方案实际上会导致另一个问题。我已经解决了次要问题,但需要一些努力。

    请记住,由于 OS3.2 或 iOS4(不确定是哪个)UIWebView 的直接子视图现在是 UIScrollView 而不是 UIScroller,所以我们可以用它做更多的事情。此外,由于访问视图的子视图不是私人操作,因此使用被转换为文档视图的子视图也不是我们可以在不违反规则的情况下对 UIWebView 做很多事情。

    首先我们需要从 UIWebview 中获取 UIScrollView:

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

    现在我们需要更改此滚动视图的委托,以便我们可以覆盖滚动视图委托调用(这实际上可能是由于此解决方案导致的次要错误,我稍后会分享):

    sview.delegate = self;
    

    现在,如果您在这一点上尝试,缩放会被破坏。我们需要实现一个 UIScrollViewDelegate 方法来修复它。添加:

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

    webBrowserView 实际上是一个 UIWebBrowserView,但这不是一个文档化的类,所以我们只是把它当作一个 UIView 来对待。

    现在运行您的应用,放大然后缩小网页。旋转,它应该会正确显示。

    这确实会导致一个相当大的错误,这可能比原来的更糟糕。

    如果您放大然后旋转,您将失去滚动能力,但您的视图仍会被放大。这是完成整个事情的修复程序。

    首先,我们需要跟踪一些数字,并定义一个标志:

    我在我的 h 文件中定义了这些:

    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 都会被调用。 performSelector 延迟 0.0 秒的原因是因为我们想在下一个 runloop 上调用 adjustWithZoomData。如果直接调用,adjustWithZoomData 会根据之前的方向进行调整。

    这里是 adjustWithZoomData 方法:

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

    就是这样!现在,当您旋转时,它将保持缩放,并大致保持正确的偏移量。如果有人想对如何获得准确的偏移量进行数学计算,那就去做吧!

    【讨论】:

    • 我想我没有提到,我认为这首先是一个错误。
    • 我还注意到这会破坏双击以进行缩小,排序。
    • 嗨 maxpower,是否有关于 UIWebView 的视图数组的文档?如果 WebBrowserView 是 objectAtIdx:10,哪个条目应该是 pdf/jpg/png-documents 直接加载到 UIWebView 中?
    • @iFloh - 这完全没有文档记录,并且将来可能会发生变化,所以我会非常小心地在运输应用程序中使用这样的东西。如果 Apple 更改此视图的工作方式(就像他们经常对此类未记录的 UI 元素所做的那样),您的应用程序可能会崩溃。
    【解决方案2】:

    我发现了一些对我有用的东西。问题是当 uiwebview 改变它的方向时,web 内容被缩放以适应视口。但是滚动视图子视图的缩放比例参数没有正确更新(也没有更新 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;
        }
    }
    

    希望这会有所帮助!

    【讨论】:

    • 感谢您的解决方案!我已经修复了代码,因此任何人都可以更轻松地在他们的 ViewController.m 中实现(代码也复制到 gist.github.com/834907
    • 它仍然对动画做了一些奇怪的事情,但是谢谢 ;) 它比以前更好了!我想知道苹果到底做了什么来解决这个问题……我认为他们有某种无证类可以提供修复。
    • 谢谢 - 有点紧张,但比以前好多了。
    • @M Penades 它工作得很好,谢谢它帮我解决了很多问题。谢谢哥们
    【解决方案3】:

    我已经尝试了 M Penades 的解决方案,这似乎也对我有用。

    我遇到的唯一问题是,在 3G 上运行时,旋转不是很顺畅。

    因此,我现在使用不同的方法:

    - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    
    CGFloat scale = browserWebView.contentScaleFactor;
    NSString *javaStuff = [NSString stringWithFormat:@"document.body.style.zoom = %f;", scale];
    [browserWebView stringByEvaluatingJavaScriptFromString:javaStuff];
    
    }
    

    最好的问候,
    拉尔夫

    【讨论】:

    • 它确实适用于倾斜 UIWebView M Penades 答案完美。这个答案的另一个坏处是,每次设备旋转时,javascript都会调用这个'会导致内存警告。所以上面的答案是最好的。
    • 我在 iOS8 内部 -viewWillTransitionToSize:withTransitionCoordinator: 中使用它来强制在旋转后调整内部 UIWebBrowserView 组件的大小。接受的答案无效。
    • @Jano,你能详细解释一下你到底做了什么吗,我有同样的问题 - UIWebBrowserView 在 ios8 上旋转时放错了位置
    • @Martin -(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { CGFloat scale = self.webView.contentScaleFactor;NSString *js = [NSString stringWithFormat:@"document .body.style.zoom = %f;", scale];[self.webView stringByEvaluatingJavaScriptFromString:js]; }
    【解决方案4】:

    我自己正在研究这个并发现了更多信息:

    更改缩放时的问题:

    1. 即使缩放级别更改,Safari 也经常无法正确重绘(如果有的话)。
    2. 更改宽度会强制重新绘制。
    3. 您会认为横向中的 width=device-width 会使用 1024,但它似乎使用 768(screen.width 也会发生)。

    例如如果当前宽度为 1024 并且您想在横向中从 1 缩放到 1.5,您可以:

    • 更改宽度和缩放的组合,例如宽度到 2048 并缩放到 0.75
    • 将宽度更改为 1023(难看的锯齿?)
    • 将宽度更改为 1023,然后将下一行改回 1024(两次重绘,但至少要重绘窗口)。

    【讨论】:

      【解决方案5】:

      显然我最终没有使用 M Penades 的解决方案(忘记更新这篇文章!抱歉)。

      我所做的是调整整个文档的大小(并更改我的字体大小以保持比例)。这显然解决了问题。

      但是,我的 UIWebView 仅用于从 iOS 文件系统加载我自己的 HTML 和 CSS - 如果您正在构建通用 Web 浏览器,则此技巧可能无法正常工作。

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

      要点https://gist.github.com/d6589584944685909ae5

      【讨论】:

        【解决方案6】:

        我发布这个是因为我也遇到了同样的问题,在这里我遵循M Penades 方法。M Penades 的答案仅适用于用户不倾斜(捏出)Webview 然后旋转的情况设备并重复此过程。然后 UiwebView 的内容大小逐渐减小。所以这就是问题出现在M Penades 答案中。所以我也解决了这个问题,我的代码如下。

        1) 为此,我设置了捏合手势,以便当用户倾斜时 UIwebView 可以检查 UIwebView 的缩放大小。 //一个这个请在'.h文件'中导入UIGestureRecognizerDelegate协议

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

        如果用户在这种情况下捏入/拉出 Web 视图,只需设置 THat Zooming Factor 。 这样 WebView 就可以根据 Oreintaion 的变化调整其 ContentSize。

        - (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 也非常有效。

        【讨论】:

          【解决方案7】:
          - (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

          【讨论】:

            【解决方案8】:

            在旋转时,尝试将 scrollView zoomScale 设置为 0。 在这里查看我的完整答案:UIWebView content not adjusted to new frame after rotation

            【讨论】:

              猜你喜欢
              • 2023-04-04
              • 1970-01-01
              • 2014-01-18
              • 1970-01-01
              • 2015-12-17
              • 2013-11-05
              • 1970-01-01
              • 2011-02-10
              • 1970-01-01
              相关资源
              最近更新 更多