XCODE/Swift Autolayout ScrollView with dynamic label, textview etc. How set scrollview height based on textview

I am using: Swift, autolayout and creating all views in storyboard. I do modify the content programatically. I have following design; black boxes is pictures, below picture a date and topic, below that a title, and at the bottom I have a textview which gets loaded from a websource. I have disabled scroll on textview, as I want only the scrollview to scroll. So how would be the best way to solve this, so i will be able to scroll to the bottom of the textview, showing me all the text?

My idea is to somehow retrieve the contentheight of the textview after loading contents into it (ViewDidLoad). Then add this to the height of the scrollview deducted from the original height of the textview. But must say, it seems tough for something which i thought would be standard functionality. Any ideas on this?

My code does look like this, so far, but it doesn't seem to work:

override func viewDidAppear(animated: Bool)
 {
    println("Height: \(self.textView.frame.height)") // prints 222.0
    let contentSize = self.textView.sizeThatFits(self.textView.bounds.size)
    var frame = textView.frame
    frame.size.height = contentSize.height
    textView.frame = frame
    println("Height: \(self.textView.frame.height)") // prints 283.5
 }
override func viewDidLoad() 
{
    super.viewDidLoad()
    self.textView.layoutIfNeeded()
    println("Height: \(self.textView.frame.height)")  //prints 222.0

    //self.textView.delegate = self
}

Code Example 2:

let sizeThatFits = CGSizeMake(self.textView.frame.size.width, CGFloat(MAXFLOAT))
    //CGSize sizeThatFits = [self.textView sizeThatFits:CGSizeMake(self.textView.frame.size.width, MAXFLOAT)]
    self.textViewHeight = sizeThatFits.height

Error Message: NSNumber is not a subtype of NSLayoutConstraint.

Below seems to be okay with syntax. Code Example 3:

self.textView.addObserver(self, forkeypath: "contentSize", options: NSKeyValueObservingOptions, context: nil)

Screenshot of design

Constraints


ANSWERS:


Scrollviews are a little bit complicated when it comes to auto layout, which makes working with them more difficult.

You probably have a width and height constraint for you textView in the storyboard(otherwise you will have ambiguous contentSize warnings for the scrollView).

I found a solution for your problem, just tried it out and it works great.

First, you need to create an outlet from the UITextView height constraint in your viewController:

@interface ViewController ()

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewHeightConstraint;

@end

Then, in viewDidLoad you add yourself as an observer for the contentSize property on the textView

- (void)viewDidLoad {
    [super viewDidLoad];
    // All you other stuff ...

    [self.textView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionInitial context:nil];
}

Then in the observeValueForKeyPath, you update the height constraint for the textView, something like this:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    [self.textViewHeightConstraint setConstant:self.textView.contentSize.height];
}

Then don't forget to remove the observer so you don't have a crash

- (void)dealloc {
    [self.textView removeObserver:self forKeyPath:@"contentSize"];
}

For this to work you have to make sure you have top and bottom offset constraints from the textView to the scrollView.

If you need more help, just let me know.


Update - Swift

This is how your implementation should look like if you are using swift

class YourViewController: UIViewController {

    @IBOutlet weak var textView: UITextView!
    @IBOutlet weak var textViewHeightConstraint: NSLayoutConstraint!

    override
    func viewDidLoad (){
        textView.addObserver(self, forKeyPath: "contentSize", options:NSKeyValueObservingOptions.New, context: nil)
    }

    override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
        textViewHeightConstraint.constant = textView.contentSize.height
    }

    deinit {
        self.textView.removeObserver(self, forKeyPath: "contentSize")
    }
}

You can add the height constraint of the text view as IBOutlet to your file. After loading, it's a simple update:

CGSize sizeThatFits = [self.textView sizeThatFits:CGSizeMake(self.textview.frame.size.width, MAXFLOAT)];

self.textViewHeightConstraint.constant = sizeThatFits.height;


 MORE:


 ? height of the text view to be dynamic inside a scrollview
 ? I want to enable ScrollView in TextView.When TextView Height Is Increased
 ? Autolayout ScrollView with dynamic content
 ? Using a textView and ScrollView in the same ViewController does not work? Swift
 ? How to adjust the height of a textview to his content in SWIFT?
 ? How to dynamically adjust height of UITextView
 ? Get number of lines in UITextView without contentSize.height
 ? Get number of lines in UITextView without contentSize.height
 ? Get number of lines in UITextView without contentSize.height
 ? Background Image for UITextView