How to determine the content size of a UIWebView?

后端 未结 15 1901
灰色年华
灰色年华 2020-11-22 17:06

I have a UIWebView with different (single page) content. I\'d like to find out the CGSize of the content to resize my parent views appropriately. T

相关标签:
15条回答
  • 2020-11-22 17:20

    This's weird!

    I tested the solutions both sizeThatFits: and [webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] are NOT working for me.

    However, I found an interesting easy way to get the right height of webpage content. Currently, I used it in my delegate method scrollViewDidScroll:.

    CGFloat contentHeight = scrollView.contentSize.height - CGRectGetHeight(scrollView.frame);
    

    Verified in iOS 9.3 Simulator/Device, good luck!

    EDIT:

    Background: The html content is calculated by my string variable and HTTP content template, loaded by method loadHTMLString:baseURL:, no registered JS scripts there.

    0 讨论(0)
  • 2020-11-22 17:22

    I have another solution that works great.

    On one hand, Ortwin's approach & solution works only with iOS 6.0 and later, but fails to work correctly on iOS 5.0, 5.1 and 5.1.1, and on the other hand there is something that I don't like and can't understand with Ortwin's approach, it's the use of the method [webView sizeThatFits:CGSizeZero] with the parameter CGSizeZero : If you read Apple Official documentation about this methods and its parameter, it says clearly :

    The default implementation of this method returns the size portion of the view’s bounds rectangle. Subclasses can override this method to return a custom value based on the desired layout of any subviews. For example, a UISwitch object returns a fixed size value that represents the standard size of a switch view, and a UIImageView object returns the size of the image it is currently displaying.

    What I mean is that it's like he came across his solution without any logic, because reading the documentation, the parameter passed to [webView sizeThatFits: ...] should at least have the desired width. With his solution, the desired width is set to the webView's frame before calling sizeThatFits with a CGSizeZero parameter. So I maintain this solution is working on iOS 6 by "chance".

    I imagined a more rational approach, which has the advantage of working for iOS 5.0 and later... And also in complex situations where more than one webView (With its property webView.scrollView.scrollEnabled = NO is embedded in a scrollView.

    Here is my code to force the Layout of the webView to the desired width and get the corresponding height set back to the webView itself:

    Obj-C

    - (void)webViewDidFinishLoad:(UIWebView *)aWebView
    {   
        aWebView.scrollView.scrollEnabled = NO;    // Property available in iOS 5.0 and later 
        CGRect frame = aWebView.frame;
    
        frame.size.width = 200;       // Your desired width here.
        frame.size.height = 1;        // Set the height to a small one.
    
        aWebView.frame = frame;       // Set webView's Frame, forcing the Layout of its embedded scrollView with current Frame's constraints (Width set above).
    
        frame.size.height = aWebView.scrollView.contentSize.height;  // Get the corresponding height from the webView's embedded scrollView.
    
        aWebView.frame = frame;       // Set the scrollView contentHeight back to the frame itself.
    }
    

    Swift 4.x

    func webViewDidFinishLoad(_ aWebView: UIWebView) {
    
        aWebView.scrollView.isScrollEnabled = false
        var frame = aWebView.frame
    
        frame.size.width = 200
        frame.size.height = 1
    
        aWebView.frame = frame
        frame.size.height = aWebView.scrollView.contentSize.height
    
        aWebView.frame = frame;
    }
    

    Note that in my example, the webView was embedded in a custom scrollView having other webViews... All these webViews had their webView.scrollView.scrollEnabled = NO, and the last piece of code I had to add was the calculation of the height of the contentSize of my custom scrollView embedding these webViews, but it was as easy as summing my webView's frame.size.height computed with the trick described above...

    0 讨论(0)
  • 2020-11-22 17:22

    I'm using a UIWebView that isn't a subview (and thus isn't part of the window hierarchy) to determine the sizes of HTML content for UITableViewCells. I found that the disconnected UIWebView doesn't report its size properly with -[UIWebView sizeThatFits:]. Additionally, as mentioned in https://stackoverflow.com/a/3937599/9636, you must set the UIWebView's frame height to 1 in order to get the proper height at all.

    If the UIWebView's height is too big (i.e. you have it set to 1000, but the HTML content size is only 500):

    UIWebView.scrollView.contentSize.height
    -[UIWebView stringByEvaluatingJavaScriptFromString:@"document.height"]
    -[UIWebView sizeThatFits:]
    

    All return a height of 1000.

    To solve my problem in this case, I used https://stackoverflow.com/a/11770883/9636, which I dutifully voted up. However, I only use this solution when my UIWebView.frame.width is the same as the -[UIWebView sizeThatFits:] width.

    0 讨论(0)
  • 2020-11-22 17:24

    I'm also stuck on this problem, then I realized that if I want to calculate the dynamic height of the webView, I need to tell the width of the webView first, so I add one line before js and it turns out I can get very accurate actual height.

    The code is simple like this:

    -(void)webViewDidFinishLoad:(UIWebView *)webView
    {
    
        //tell the width first
        webView.width = [UIScreen mainScreen].bounds.size.width;
    
        //use js to get height dynamically
        CGFloat scrollSizeHeight = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
        webView.height = scrollSizeHeight;
    
        webView.x = 0;
        webView.y = 0;
    
        //......
    }
    
    0 讨论(0)
  • 2020-11-22 17:29

    It turned out that my first guess using -sizeThatFits: was not completely wrong. It seems to work, but only if the frame of the webView is set to a minimal size prior to sending -sizeThatFits:. After that we can correct the wrong frame size by the fitting size. This sounds terrible but it's actually not that bad. Since we do both frame changes right after each other, the view isn't updated and doesn't flicker.

    Of course, we have to wait until the content has been loaded, so we put the code into the -webViewDidFinishLoad: delegate method.

    Obj-C

    - (void)webViewDidFinishLoad:(UIWebView *)aWebView {
        CGRect frame = aWebView.frame;
        frame.size.height = 1;
        aWebView.frame = frame;
        CGSize fittingSize = [aWebView sizeThatFits:CGSizeZero];
        frame.size = fittingSize;
        aWebView.frame = frame;
    
        NSLog(@"size: %f, %f", fittingSize.width, fittingSize.height);
    }
    

    Swift 4.x

    func webViewDidFinishLoad(_ webView: UIWebView) {
        var frame = webView.frame
        frame.size.height = 1
        webView.frame = frame
        let fittingSize = webView.sizeThatFits(CGSize.init(width: 0, height: 0))
        frame.size = fittingSize
        webView.frame = frame
    }
    

    I should point out there's another approach (thanks @GregInYEG) using JavaScript. Not sure which solution performs better.

    Of two hacky solutions I like this one better.

    0 讨论(0)
  • 2020-11-22 17:29

    Also in iOS 7 for proper working of all of mentioned methods add this in your view controller viewDidLoad method:

    if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {
        self.automaticallyAdjustsScrollViewInsets = NO;
    }
    

    Otherwise neither of methods would work as it should.

    0 讨论(0)
提交回复
热议问题