0
votes

I've searched around for help on this here, but I have yet to get any of the solutions to work right. Here is an example, which hasn't worked for me yet.

Here is the xib I'm working with. There is an outterView and slightly offset innerView (in order to get the thick blue line on the left. Inside there is a UILabel, UITextView, UILabel and UITextView. Plus the two UIButtons, which I can make hug the bottom of the view.

XIB Image: xib

The challenge is that the two UITextViews contain dynamic length content. They can grow, and then the inner/outter views must grow as well. Below is how I've tried to do this, with some variations, but no reliable success. There is either jumbled text, overlapped, text, buttons on top of text, etc.

// viewDidLoad (or in loadView)
-(void)viewDidLoad {
    [super viewDidLoad];

    // set UITextView text
    [warmupDesc setText:[workout objectForKey:@"warmup_description"]];
    [workoutDesc setText:[workout objectForKey:@"workout_description"]];

    // warmup sizeToFit
    [self.warmupDesc sizeToFit];
    CGSize txtSize = self.warmupDesc.contentSize;
     txtSize.height = self.warmupDesc.frame.size.height;
    self.warmupDesc.contentSize = txtSize;

    // workout sizeToFit
    [self.workoutDesc sizeToFit];
    CGSize txtSize2 = self.workoutDesc.contentSize;
    txtSize2.height = self.workoutDesc.frame.size.height;
    self.workoutDesc.contentSize = txtSize2;


    // set outview height to be sum of heights of all internal items, plus padding
    outterView.frame = CGRectMake(outterView.frame.origin.x, outterView.frame.origin.y,  outterView.frame.size.width, warmupDesc.frame.size.height + workoutDesc.frame.size.height + recordBtn.frame.size.height + 60); 

    // update innerView height to match
    innerView.frame = CGRectMake(innerView.frame.origin.x, innerView.frame.origin.y, innerView.frame.size.width, outterView.frame.size.height);
}

The result is mostly like this. I'm not sure the UITextView's even resized (default is 85px). The bottom one should be at least twice as big as it is. And the buttons overlap, showing the addition logic for the outterView's isn't working well.

Any tips on properly laying this out, or better methods to auto-size? I've avoided UITextviews for this reason until now, is there a better element?

Result Image:simulator

2
"I'm not sure the UITextView's even resized" because of self.workoutDesc.contentSize = txtSize2; ... you are setting the contentSize, not frame. - staticVoidMan

2 Answers

0
votes

Try this:

-(void)viewDidLoad
{
    //...

    //warmup sizeToFit
    [self.warmupDesc sizeToFit];
    CGRect warmUpFrame = self.warmupDesc.frame;
    warmUpFrame.size.height = self.warmupDesc.contentSize.height;
    self.warmupDesc.frame = warmUpFrame;

    //workout sizeToFit
    [self.workoutDesc sizeToFit];
    CGRect workoutDescFrame = self.workoutDesc.frame;
    workoutDescFrame.height = self.workoutDesc.contentSize.height;
    self.workoutDesc.frame = workoutDescFrame;

    //...
}

but now it's all gonna go down, way down.
Have you handled the scenario when the buttons go out of visible view?
Like using UIScrollView?

0
votes

Following up. I found the below getContentSize function's method of getting the height of a UITextView to be fairly effective. It seems though that it tended to be slightly short for small text, and overly-large for larger text, so I made the adjustment that seemed to help (+10, *.80). But this has worked quite well otherwise.

{

    self.warmupDesc.frame = CGRectMake(self.warmupDesc.frame.origin.x, self.warmupName.frame.origin.y + self.warmupName.frame.size.height - 7, self.warmupDesc.frame.size.width, ([self getContentSize: warmupDesc].height + 10) * .80);

}


-(CGSize) getContentSize:(UITextView*) myTextView{
    CGRect frame = [myTextView.text boundingRectWithSize:CGSizeMake(myTextView.frame.size.width, FLT_MAX)
                                  options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                  attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]}
                                  context:nil];
    return frame.size;
}