代码之家  ›  专栏  ›  技术社区  ›  choonkeat

缩放操作+uiInterfaceOrientation更改后,iPhone uiWebView宽度不合适

  •  13
  • choonkeat  · 技术社区  · 14 年前

    我创建了一个带有uiwebview(scales page to fit=yes,shouldAtotateToInterfaceOrientation=yes)的裸骨iPhone应用程序,并加载了一个网页,例如。 https://stackoverflow.com/

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

    错误的 :放大页面并缩小。现在旋转设备会在某个方向上以奇怪的宽度显示uiwebview(如果您放大横向,则纵向宽度会很奇怪,反之亦然)。只有在导航到其他页面时,此行为才被修复。

    对的 :在Mobile Safari中加载相同的URL。旋转工作和宽度适合,而不考虑缩放操作。

    这是uiwebview错误吗(可能不是)?或者有什么事情需要做才能使事情“只起作用”,比如在MobileSafari?

    8 回复  |  直到 10 年前
        1
  •  14
  •   choonkeat    14 年前

    我找到了对我有用的东西。问题是,当uiWebView改变其方向时,Web内容将被缩放以适应视区。但是ScrollView子视图的ZoomScale参数没有正确更新(也没有更新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;
        }
    }
    

    希望这有帮助!

        2
  •  4
  •   Ralph    13 年前

    我试过用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];
    
    }
    

    最好的问候,
    拉尔夫

        3
  •  4
  •   storoj    12 年前
    - (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

        4
  •  1
  •   Parth Bhatt    11 年前

    我发布这篇文章是因为我也面临同样的问题,现在我关注的是 M Penades 方法。 M字幕 只有当用户不扭曲(捏出)WebView,然后旋转设备并重复此过程,uiWebView的内容大小才会逐渐减小。所以问题来了 M字幕 回答。所以我也解决了这个问题,我的代码如下。

    1)为此,我设置了捏手势,这样当用户倾斜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;
      }
    

    返回“是”保证允许同时识别。返回“否”并不保证阻止同时识别,因为其他手势的代表可能返回“是”。

     -(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在这种情况下收缩/缩小Web视图,只需设置缩放系数。 这样WebView就可以随着_或内容的更改而调整其内容大小。

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

        5
  •  0
  •   maxpower    14 年前

    我有解决这个问题的办法,但我得说我不太喜欢这个问题。它工作得很好,但解决方案实际上会导致另一个问题。我有一个解决第二个问题的方法,但这需要一些努力。

    请记住,由于os3.2或ios4(不确定哪个)uiwebview的直接子视图现在是uiscrollview而不是uiscroller,所以我们可以用它做更多的事情。此外,由于访问视图的子视图不是私有操作,也不使用作为文档视图的子视图,因此我们可以在不违反规则的情况下对uiWebView进行大量操作。

    首先,我们需要从uiWebView获取uiScrollView:

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

    现在,我们需要更改此ScrollView的委托,以便可以覆盖ScrollView委托调用(这可能是由于此解决方案而导致的第二个bug的原因,稍后我将与大家分享):

    sview.delegate = self;
    

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

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

    WebBrowserView实际上是一个UIWebBrowserView,但它不是一个文档化的类,所以我们只将其作为一个UIView来处理。

    现在运行应用程序,放大然后缩小网页。旋转,应正确显示。

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

    如果你放大然后旋转,你将失去滚动能力,但你的视图将仍然放大。这是完成整件事的方法。

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

    我在我的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秒的原因是我们希望在下一个运行循环上调用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;
    }
    

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

        6
  •  0
  •   robocat    13 年前

    我自己也在调查这件事,发现了更多的信息:

    更改缩放时出现的问题:

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

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

    • 更改宽度和缩放的组合,例如宽度为2048,缩放为0.75
    • 将宽度更改为1023(难看的混叠?)
    • 将宽度改为1023,然后将下一行改回1024(两次重新绘制,但至少要重新绘制窗口)。
        7
  •  0
  •   choonkeat    12 年前

    所以很明显,我最终没有使用m penades的解决方案(而且忘了更新这篇文章!对不起)。

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

    但是,我的uiwebview只用于从iOS文件系统加载我自己的HTML&css—如果您正在构建通用的Web浏览器,那么这个技巧可能不会很好地发挥作用。

    视图控制器.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

        8
  •  0
  •   Community CDub    7 年前

    在旋转时,尝试将滚动视图缩放比例设置为0。 请看我的完整答案: UIWebView content not adjusted to new frame after rotation