How to set content size of UIScrollView dynamically

I got question about UIScrollview.

The story is I have a UIView named ChartsView which I re-draw it myself by override method drawRect(). The content of drawing was generated dynamically. So I do not know its size until runtime. The question is how/where can I set its super view’s (scrollView) content size dynamically?Any idea about that?

  • Force symbolicatecrash to use a specific .app and .dSYM file?
  • ViewDidAppear is not called when opening app from background
  • Get the device's phone number programmatically
  • Accessing a view controller created through Storyboard using the App Delegate
  • How can one develop iPhone apps in Java?
  • How to use MKMapView finished loading delegate, possible “finished displaying” delegate?
  •     - (void)viewDidLoad
        {
            [super viewDidLoad];
    
    // not this way. it's fixed size.....
            ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)]; 
    
            self.scrollView.contentSize = chartsView.frame.size;
    
            [self.scrollView addSubview:chartsView];
    
        }
    

    7 Solutions Collect From Internet About “How to set content size of UIScrollView dynamically”

    One more easy way

    - (void)viewDidLoad
    {
        float sizeOfContent = 0;
        UIView *lLast = [scrollView.subviews lastObject];
        NSInteger wd = lLast.frame.origin.y;
        NSInteger ht = lLast.frame.size.height;
    
        sizeOfContent = wd+ht;
    
        scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, sizeOfContent);
    }
    

    swift (2.0)

    @IBOutlet weak var btnLatestButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        let height = btnLatestButton.frame.size.height
        let pos = btnLatestButton.frame.origin.y
        let sizeOfContent = height + pos + 10
        scrollview.contentSize.height = sizeOfContent
    
    }
    

    Above ofcourse is when you just have a fixed amount of views on your scrollview.
    IOS Rocks method is available but was not good for me, created more space then I needed.

        let lastView : UIView! = scrollview.subviews.last
        let height = lastView.frame.size.height
        let pos = lastView.frame.origin.y
        let sizeOfContent = height + pos + 10
        scrollview.contentSize.height = sizeOfContent
    

    Thanks to IOS Rocks and CularBytes for the leads on this. I found two problems (for me) with the above solutions:

    1. I always have a container UIView as the only child of my UIScrollView, so I had to update the way I look up the last view in that child UIView (see below)
    2. I am offset’ing my content in the UIScrollView and as such needed to calculate the absolute position of that last UIView (so, relative to the window not the parent view)

    Also I am using autolayout to pin the sides of the UIScrollView, so I don’t need to worry about width (as is CularBytes).

    Here’s what I came up with and works (in Swift 3.0):

    func setScrollViewContentSize() {
    
        var height: CGFloat
        let lastView = self.myScrollView.subviews[0].subviews.last!
        print(lastView.debugDescription) // should be what you expect
    
        let lastViewYPos = lastView.convert(lastView.frame.origin, to: nil).y  // this is absolute positioning, not relative
        let lastViewHeight = lastView.frame.size.height
    
        // sanity check on these
        print(lastViewYPos)
        print(lastViewHeight)
    
        height = lastViewYPos + lastViewHeight
    
        print("setting scroll height: \(height)")
    
        myScrollView.contentSize.height = height
    }
    

    I call this in my viewDidAppear() method.

    try this

    - (void)viewDidLoad
            {
                [super viewDidLoad];
    
        // not this way. it's fixed size.....
                ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)]; 
    
                self.scrollView.contentSize = chartsView.frame.size;
                [self.scrollView setNeedsDisplay];
                [self.scrollView addSubview:chartsView];
    
        }
    

    Try this –

    - (void)viewDidLoad
        {
            [super viewDidLoad];
    
    // not this way. it's fixed size.....
            ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)]; 
    
            //self.scrollView.contentSize = chartsView.frame.size;
            [self.scrollView setContentSize:CGSizeMake(chartsView.frame.size.width, chartsView.frame.size.height)];
            [self.scrollView addSubview:chartsView];
    
        }
    

    It is not 100% guaranteed that the last object in scrollView.subviews array will return the highest y-origin object in your scroll view. The subviews array is arranged by Z-Index (i.e the last object in the subviews array will be the object stacked the highest and will be the top-most subview in the scroll view’s subviews. Instead it is more accurate to use a basic sort function to iterate through the subviews and get the object with the highest y-origin.

    Here is a basic function in swift 3 that that can do so:

    func calculateContentSize(scrollView: UIScrollView) -> CGSize {
        var topPoint = CGFloat()
        var height = CGFloat()
    
        for subview in scrollView.subviews {
            if subview.frame.origin.y > topPoint {
                topPoint = subview.frame.origin.y
                height = subview.frame.size.height
            }
        }
        return CGSize(width: scrollView.frame.size.width, height: height + topPoint)
    }
    

    Usage (in viewDidLayoutSubviews or whenever your content size updates):

    scrollView.contentSize = calculateContentSize(scrollView: scrollView)
    

    UPDATE SWIFT 4

    Here is a more consise version in swift 4

    extension UIScrollView {
        func updateContentView() {
            contentSize.height = subviews.sorted(by: { $0.frame.maxY < $1.frame.maxY }).last?.frame.maxY ?? contentSize.height
        }
    }
    

    Usage:

    myScrollView.updateContentView()
    

    This is an extension written on Swift 3

    extension UIScrollView {
        func updateContentViewSize() {
            var newHeight: CGFloat = 0
            for view in subviews {
                let ref = view.frame.origin.y + view.frame.height
                if ref > newHeight {
                    newHeight = ref
                }
            }
            let oldSize = contentSize
            let newSize = CGSize(width: oldSize.width, height: newHeight + 100)
            contentSize = newSize
        }
    }