iosautolayoutstoryboardconstraintsuitextview

Autolayout interaction of Storyboard elements with UI elements created programmatically using Objective-C and Swift


Because, I have a very complicated storyboard, I thought it would be a good idea to add conditional elements programmatically. In particular, if the text for a UILabel in the storyboard is too great, I would like to place the text in a scrollable UITextView with fixed height. The label is set to 0 lines so it expands vertically. However with long text, either you must truncate or the label gets too big since it is not scrollable.

The problem is when I programatically add the textView to the viewController, the autolayout constraints know nothing about the textView and do not adjust.

Is it necessary for me to manually adjust all the constraints using outlets, or can anyone suggest a way to get the UI elements to adjust automatically to the programmatic addition of a UITextView in place of the UILabel. Right now I am adding the UITextView as a subView of the overall contentView for the VC. SHould I perhaps be adding it as a subView of the label? Would appreciate any suggestions.

Here is my code so far:

if (mytext.length >= 32) {
         [self swapTextviewWith:mytext];//create a textview and put in the textview
    }
    else {
        self.messageLabel.text = mytext;//put in label
       
    }

-(void) swapTextviewWith: (NSString*) text {
    UITextView * tv = [UITextView new];
    CGRect aFrame = self.messageLabel.frame;
    aFrame.size.height = 100;
    tv.frame = aFrame;
    self.messageLabel.hidden = YES;
    [self.contentView addSubview: tv];
    tv.text = text;
    UIFont *font=[UIFont fontWithName:@"Arial" size:16.f];
    tv.font = font;
    [tv setNeedsDisplay];
}

Solution

  • There is absolutely nothing wrong with having some of your subviews come from the storyboard and other subviews come from code. I can think of other solutions to the problem (for example, one easy way to make two views swappable is to make them both arranged subviews of a stack view and then just hide one or the other), but let's just talk as if the way you're proposing to do this is the way you're going to do it.

    Is it necessary for me to manually adjust all the constraints using outlets

    Yes. You have to set the text view's translatesAutoresizingMaskIntoConstraints to false and add constraints between it and other views as desired (you will need references to those views in order to do this, obviously, and those references can certainly come from outlets).

    Your code leaves messageLabel in place (though invisible), so if there are constraints to it in the storyboard, those constraints will still be present. Under normal circumstances (i.e. not inside a stack view), a hidden view is still a view in the interface and constraints to it still work. You might, therefore, need references to those constraints, too, so you can deactivate them; otherwise you can wind up with constraint conflicts and things will not display correctly.

    On the other hand, it looks to me like you could simply pin the text view to messageLabel on all four sides and then just proceed to give messageLabel an absolute height constraint. That would sure simplify your approach!