UIScrollView not scrollable using autolayout and dynamic constraints - ios

I have a view which contains a scrollview, a containerview and 3 subviews (topview, textview and bottomview). See the view's hierachy below. The height of the textview is defined based on its content. I defined a dynamic constraint for its height and I change it in viewDidLayoutSubviews. The size of the textview is correct but the problem is that my scrollview is not scrolling. What I am doing wrong? Perhaps I need to add/modify some of the other constraints?
-(void)viewDidLayoutSubviews
{
NSAttributedString * string = [[NSAttributedString alloc] initWithString:self.game.description];
CGFloat heightTV = [self textViewHeightForAttributedText:string andWidth:260];
self.dynamicTVHeight.constant = heightTV;
[self.view layoutIfNeeded];
}
- (CGFloat)textViewHeightForAttributedText:(NSAttributedString *)text andWidth:(CGFloat)width
{
UITextView *textView = [[UITextView alloc] init];
[textView setAttributedText:text];
CGSize size = [textView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}

The UIScrollView scroll only if it has contentSize bigger than bounds. Content size of UIScrollView can be set automatically by calculating frames of subviews (calculated from constraints) or manually in code (usually in viewDidLoad).
Double check your UIScrollView's contentSize.

Related

UITextField - UIView Resize Programmatically

Am programmatically creating a UIView, setting the frame for the view, then adding a UITextField inside the view. I've been stuck on this one for a while, I'm trying to get the whole UIView to resize based on the amount of words in the text field if that makes sense?
Thanks,
Declan
Assuming you have a given width, you can use sizeThatFits:
Here below is code I use for UITextViews. Similar code can be used for UITextFields.
Example:
UITextView *myTextView = [[UITextView alloc] init];
[myTextView setAttributedText:myAttributedString];
CGSize size = [myTextView sizeThatFits:CGSizeMake(width, FLT_MAX)];
CGRect frame = CGRectMake(0, 0, width, size.height);
myTextView.frame = frame;

Adding a label to a scroll view in iOS

I would like to add a label to a scroll view. This is being done in main controller. However, when I do the following the label is on overlaying the contents of scroll view. I want the label to be exactly on top and then the rest of the scroll view contents.
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.contentView.frame.size.width, 80)];
label.backgroundColor = [UIColor greenColor];
label.text = #"Testing";
[self.scrollView addSubview: label];
[self.scrollView setNeedsDisplay];
Unfortunately, there is a little more to doing this programmatically. I'd highly recommend that you add this label to your xib or storyboard and not do this programmatically but if that isn't an option for what ever reason then there is only one thing you can do. You'll need to iterate over your scrollView's children and push each of the down slightly to make room for your new label, then set the label at the top of the scrollView.
Very simple example, this may not be working perfectly so you'll need to tweak it to what you need/want.
// Set the amount of y padding to push each subview down to make room at the top for the new label
CGFloat yPadding = 80.0f;
CGFloat contentWidth = CGRectGetWidth(self.contentView.frame);
UILabel* label = [[UILabel alloc] initWithFrame:(CGRect){CGPointZero, contentWidth, 44.0f}];
label.text = #"Testing";
// Iterate over each subview and push it down by the amount set in yPadding. Also, check for the subview with the lowest y value and set that as your labels y so that it is at the top of the scrollView.
for (UIView* subview in self.scrollView.subviews) {
CGRect subviewFrame = subview.frame;
CGFloat currentLabelY = CGRectGetMinY(label.frame);
// Set the labels y based off the subview with the lowest y value
if (currentLabelY == 0.0f || (currentLabelY > CGRectGetMinY(subviewFrame))) {
CGRect labelFrame = label.frame;
labelFrame.origin.y = subviewFrame.origin.y;
label.frame = labelFrame;
}
// Push the subview down by the amount set in yPadding
subviewFrame.origin.y += yPadding;
subview.frame = subviewFrame;
}
// Finally, add the label as a subView of the scrollView
[self.scrollView addSubview:label];
You should add the label as a subview of the scrollview:
[self.scrollView addSubview:label]

UITextView within UIScrollView - Dynamic Heights?

I have a UIView which contains a UIScroller - which in turn contains a couple of labels, one image and a dynamic text view.
The text view can contain anything from a few characters to 2000 words - how can I automatically apply the relevant heights to the UITextView and the parent scroller?
I have got as far as the following -
//Set Scroller
[self.scrollerArticle setScrollEnabled:YES];
[self.scrollerArticle setContentSize:CGSizeMake(320, 750)];
[self.articleUITextView sizeToFit];
[self.articleUITextView layoutIfNeeded];
But don't know how to apply the sizetofit method to the scroller?
Try like this,
[self.scrollerArticle setContentSize:CGSizeMake(320, CGRectGetMaxY(self.articleUITextView.frame))];
UITextView is a subclass of UIScrollView and you should use content size after you set up a text to get the size:
self.articleUITextView.text = #"YOUR TEXT";
CGRect rec = self.articleUITextView.frame;
rec.size.height = self.articleUITextView.contentSize.height;
textView.frame = rec;
After that you can just chance contentSize of your scroll view.
If you want to use sizeWithFont: it works fine for UILabels but not necessary with UITextView.
You can get the height of the content using the below method.
-(CGFloat)getContentHeight{
NSString *aMessage = #"My Name is ABC"; // Can be anything between 0 to 2000 chars
CGSize maximumSize = CGSizeMake(320, 9999);
// Use the font you are willing to use for TexTView.
UIFont *textFont = [UIFont fontWithName:#"Helvetica-Bold" size:MessageFontSize];
CGSize myStringSize = [aMessage sizeWithFont:textFont
constrainedToSize:maximumSize
lineBreakMode:NSLineBreakByWordWrapping];
return myStringSize.height;
}
And then can set the ContentSize of Scrollview accordingly.

How to keep the text of cell label at top when cell's height increases?

I am increasing cell's height in the method heightForRowAtIndexPath, as a result of it, the label is coming centered.
How do make sure that label is still at top with the text irrespective of the height of the row?
While allocating UITableViewCell, you need to do like this..
UITableViewCell * cell;
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:string];
At the time of initialization with style: UITableViewCellStyleSubtitle will come.
Hope this will work..
You can do it in two ways.
Create a custom label and set it's frame.
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT)];
[cell.contentView addSubView:lbl];
Use a UITableViewCell subclass and override -layoutSubviews. In this method, you'll want to call [super layoutSubviews].
- (void)layoutSubviews {
[super layoutSubviews];
CGSize size = self.bounds.size;
CGRect frame = CGRectMake(0.0f, 0.0f, size.width, size.height);
self.textLabel.frame = frame;
self.textLabel.contentMode = UIViewContentModeScaleAspectFit;
}
Write Following Code:
UILabel *myLable = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, width, height)];
[cell.contentView addSubView: myLable];
If Also You want myLable fram is similare to myLable.text then write..
[myLable sizeToFit];
You cannot change the position of textlabel as it is auto-adjusted.
First option is you need to subclass UITableViewCell and customize textLabel frame.
Another is that you create your own custom label and make textlabel nil. So whenever cell's height will change, your label position will not change.
Set the autolayout Top property of UILabel.
try this:
set False to "Autoresize Subviews" property of your custom cell...

Using autoResizingMask with CGRectZero

I am building a footer for a tableview's section. The height of the footer will be specified in heightForFooterInSection, so in viewForFooterInSection I would like to just add the subview and specify that the footer view should fill whatever footer height is specified (this footer size will be dynamic). So, I am using CGRectZero as the initial frame and telling the footer view to expand to fill its parent view.
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *footerView = [[UIView alloc] initWithFrame:CGRectZero];
footerView = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
footerView = [UIColor greenColor];
return footerView;
}
This works as expected - the footer of the table view is filled completely with the green view.
But now I want to add a UITextView to the footer. The text view should fill the same space, but leave a 5-point border:
{
UIView *footerView = [[UIView alloc] initWithFrame:CGRectZero];
footerView = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
footerView = [UIColor greenColor];
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectInset(footerView.frame, 5, 5)];
textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
textView.backgroundColor = [UIColor redColor];
[footerView addSubview:textView];
return footerView;
}
Instead of filling the footer view (with a 5 point margin), the text view does not appear at all. It likely has a frame of CGRectZero (or maybe even -5 x -5?). If I set the inset to 0, 0, however, it expands as expected.
What is the explanation for this? And If I can't use an inset of CGRectZero for the initial frame, what am I expected to use when the frame of the footerView can not be known?
CGRectInset will create a rectangle based on the existing rectangle. It doesn't refer to the footer view ever again: only when it is calculating it this one time. In this case, since you are trying to inset a rectangle with a zero size, this applies from the docs:
Discussion.
The rectangle is standardized and then the inset parameters are
applied. If the resulting rectangle would have a negative height or
width, a null rectangle is returned.
Therefore, you are creating your label with a null rectangle.
I would create the footer with a "typical" size, then an appropriately sized label with the autoResizingMask that you want, and then set your footerView to zero if that is what you want it set to.
I would guess that the TextView creates the content in the background, so at the moment of initialization it's empty. I usualy end up using [string sizeWithFont:constrainedToSize:lineBreakMode:]
CGSize size = [aString sizeWithFont:[UIFont systemFontOfSize:12.0] constrainedToSize:CGSizeMake(320,500) lineBreakMode:NSLineBreakByWordWrapping];
CGRect frame = CGRectMake(0, 0, size.width, size.height);

Resources