How to grow UIlabel into scrollable UIlabel? - ios

I'm trying to create a label that fits the text size. But if the text is too long it make scroll
I am trying something like that.
[containerView_ addConstraints:[NSLayoutConstraint constraintWithItem:containerView_
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0f
constant:300]];
[containerView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-bigMargin-[scrollLabel_]-bigMargin-|"
options:0
metrics:metrics
views:views]];
[containerView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-bigMargin-[scrollLabel_]-bigMargin-|"
options:0
metrics:metrics
views:views]];
[scrollLabel_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[messageLabel_]-0-|"
options:0
metrics:metrics
views:views]];
[scrollLabel_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[messageLabel_]-0-|"
options:0
metrics:metrics
views:views]];
The purpose is to show a popup with text and other stuff.
I expected my container view to grow up to 300 in height and if the message was bigger than scrolling.
But my UIScrollView gets a frame of 0 and the only thing that grows is the contentsize
Any idea how to solve this

I think UILabel are not meant to do that. You may consider using a UITextView. You may need to enable the scroll with:
textView.scrollEnabled = true

Related

How to do AutoLayout programmatically with Horizontal scrolling?

I'm trying to do Horizontal scrolling on iOS using AutoLayout programmatically. Here's the link to my github I'm trying to add another NewsSection to the next page but I'm not sure how to do it. Here's the code I'm working on.
- (void) setupNewsView
{
UIView *newsView = [[NewsSection alloc] initWithFrame:CGRectZero];
newsView.backgroundColor = [UIColor redColor];
UIView *anotherNewsView = [[NewsSection alloc] initWithFrame:CGRectZero];
anotherNewsView.backgroundColor = [UIColor blueColor];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
newsView.translatesAutoresizingMaskIntoConstraints = NO;
anotherNewsView.translatesAutoresizingMaskIntoConstraints = NO;
self.scrollView.pagingEnabled = YES;
[self.scrollView addSubview:newsView];
[self.scrollView addSubview:anotherNewsView];
NSDictionary *viewsDict = #{ #"newsView": newsView, #"anotherNewsView": anotherNewsView };
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[newsView]|"
options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom
metrics:nil
views:viewsDict]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[newsView]|"
options:0
metrics:nil
views:viewsDict]];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:newsView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f]];
[self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:newsView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeHeight
multiplier:1.0f
constant:0.0f]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[anotherNewsView(200)]|" options:0 metrics:nil views:viewsDict]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[anotherNewsView(100)]|" options:0 metrics:nil views:viewsDict]];
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * 2, self.scrollView.frame.size.height)];
Right now the app looks like this. What I want is user should be able to scroll to the right and see the blue screen. What constraint do I need to add?
The constraints you have set the blue view to fill the scroll view AND to be of a fixed width, which causes a conflict. The |s at either end of the constraint string make anotherNewsView hug the bounds of its superview (scrollView).
Try dropping the final |s from your constraints. Also position anotherNewsView to be left-aligned with newsView rather than scrollView.
These constraints should do the trick:
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[newsView(500)]" options:0 metrics:nil views:viewsDict]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[newsView(500)][anotherNewsView(100)]" options:0 metrics:nil views:viewsDict]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[anotherNewsView(200)]" options:0 metrics:nil views:viewsDict]];

iOS How to auto layout a view 3 x screen width?

I tried to place a UIView which is 3x the screen width (or 3x UIScrollView's width) in UIScrollView.
UIScrollView's width equal to the screen width.
How do I do this in AutoLayout?
If you want to do it in code via pure AutoLayout, here's how you'd do it:
- (void)layoutUserInterface {
// Placing the scrollView using AutoLayout
[self.view addSubview:self.scrollView];
// Note: The "H:" is optional, but I like to be clear
[self.view addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"H:|[scrollview]|"
options:0
metrics:nil
views:#{#"scrollview": self.scrollView}]];
[self.view addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|[scrollview]|"
options:0
metrics:nil
views:#{#"scrollview": self.scrollView}]];
// Placing the "wideView" using AutoLayout
[self.scrollView addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"H:|[wideView]"
options:0
metrics:nil
views:#{#"wideView": self.wideView}]];
[self.scrollView addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|[wideView]"
options:0
metrics:nil
views:#{#"wideView": self.wideView}]];
// Setting up the 3x width constraint
[self.scrollView addConstraint:
[NSLayoutConstraint
constraintWithItem:self.wideView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:3.0f
constant:0.0f]];
// Figure out your "wideView's" height requirements
}
Assign a value for your views's width constraint and make an IBOutlet for this in your header file.
In your m file's viewDidLoad method get the width of the current device's screen, multiply by 3 and assign to your constraint's constant. And finally call your view's layoutIfNeeded method.
Is this clear enough or do you want me to make it more clear?

NSLayoutConstraint, sub-viewing a UIView in a table view cell not working

So I am using a project that I found on Github — https://github.com/kmonaghan/CBPWordPress — and am trying to get a handle on it.
Essentially, what I want to do is create the floating "Cards" illusion that an app like Facebook has. The way that I have accomplished this in the past is by creating a subview UIView, rounding the corners, etc. before putting the title label, author name inside of that view. The issue is that I have typically done that with storyboards, while this example programmatically lays things out.
After toying around with it, I thought I had figured it out. This is how I set up the -(void)updateConstraints method:
(void)updateConstraints
{
if (!self.constraintsUpdated) {
self.contentView.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.frame), CBPLargePostPreviewTableViewCellHeight);
NSDictionary *views = #{#"postCommentLabel": self.postCommentLabel,
#"postDateLabel": self.postDateLabel,
#"postImageView": self.postImageView,
#"postTitleLabel": self.postTitleLabel,
#"roundedBackground": self.roundedBackground};
NSDictionary *metrics = #{#"padding": #(CBPPadding)};
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(4)-[roundedBackground]-(4)-|"
options:0
metrics:metrics
views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(4)-[roundedBackground]-(4)-|"
options:0
metrics:metrics
views:views]];
[self.roundedBackground addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(5)-[postTitleLabel]-(5)-[postImageView(150)]-(5)-[postDateLabel]-(5)-|"
options:0
metrics:nil
views:views]];
[self.roundedBackground addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(padding)-[postTitleLabel]-(padding)-|"
options:0
metrics:metrics
views:views]];
[self.roundedBackground addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(padding)-[postImageView]-(padding)-|"
options:0
metrics:metrics
views:views]];
[self.roundedBackground addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(padding)-[postDateLabel]-(>=0)-[postCommentLabel]-(padding)-|"
options:0
metrics:metrics
views:views]];
[self.roundedBackground addConstraint:[NSLayoutConstraint constraintWithItem:self.postCommentLabel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.postDateLabel
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0]];
self.constraintsUpdated = YES;
}
[super updateConstraints];
}
But upon running I get this error: [__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[4]'
I have tried creating bounds for the view, but to no avail. Does anybody have any suggestions? If there is a better approach to creating the effect I am looking for, I am also open to that.
It seems that you use roundedBackground in visual format strings, but have background
key in your views dict.

How do I represent the content of this UITableCell programmatically using Auto Layout?

I have just started using Auto Layout for my latest project and I was wondering what would be the most efficient way of laying out the following table cell:
Views A and B are both UILabels. C is a fixed size image and the view under A is an image that may or not be present. I am able to easily lay out A, B and C. But if the image under A is present, A's height needs to shrink proportionately and the image needs to fit underneath so that both are centered horizontally in the contentView.
I am trying to lay the entire cell out using code and the Visual Format language and have gotten quite close so far. The only problem is that the A and it's accompanying image aren't centered vertically in the container. You can see how far I have gotten in the image below:
And here is the code that I am using in my updateConstraints method. Note that with this code, I don't get an ambiguous layout:
NSDictionary *views = NSDictionaryOfVariableBindings(viewA, viewB, viewC);
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[viewA]-[viewB]-(>=8)-[viewC]-|"
options:0
metrics:nil
views:views]];
NSDictionary *metrics = #{#"width":#(40.0f), #"height":#(40.0f), #"priority":#(UILayoutPriorityRequired)};
[viewC addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewC(==width#priority)]"
options:0
metrics:metrics
views:#{#"viewC": _merchantLogo}]];
[viewC addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[viewC(==height#priority)]"
options:0
metrics:metrics
views:views]];
[viewA addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewA(>=75#750)]"
options:0
metrics:nil
views:views]];
[viewB addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewB(>=115#500)]"
options:0
metrics:nil
views:views]];
[self.contentView addConstraints:#[[NSLayoutConstraint constraintWithItem:viewC
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f],
[NSLayoutConstraint constraintWithItem:viewB
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]]];
if (!viewD) {
[self.contentView addConstraints:#[[NSLayoutConstraint constraintWithItem:viewA
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]]];
} else {
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[viewA][viewD]"
options:NSLayoutFormatAlignAllLeft
metrics:nil
views:NSDictionaryOfVariableBindings(viewA, viewD)]];
}
One of my ideas was to put A and the image below it in a container view and then lay them out within that view. But that seems kind of inefficient and I first want to make sure this isn't possible without using a container view.
So...
1.
Format
#"|-[_viewA(<=75)]-[viewB]-[viewC(==60)]-|"
Options
NSLayoutFormatAlignAllTop
2.
Format
#"V:|-[viewA]-[imageView(==10)]-|"
Options
NSLayoutFormatAlignCenterX | NSLayoutFormatAlignAllLeft
3.
Add individual constraints to constrain bottom of image view to bottom of viewB and viewC.
[NSLayotuConstraint constraintWithItem:viewB
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:imageView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0];
and other one...
This should give you what you want.

NSLayoutConstraint setup

I'm trying to setup a panel to display some information. I'm having trouble getting the autolay out to work as i want.
here's what I'm trying to do:
I have a headerView, a UIImageView and 5 labels. I want the labels to line up vertically and i want them 8 spacing from the UIImageView. I can line them up vertically easily enough:
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-[acresLabel]-[addedLabel(==acresLabel)]-[typeLabel(==acresLabel)]-[zonesLabel(==acresLabel)]-[sceneLabel(==acresLabel)]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(headerView, acresLabel, addedLabel, typeLabel, zonesLabel, sceneLabel)]];
But getting them to line up off the image view is proving tedious/verbose:
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[acresLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, acresLabel)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[addedLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, addedLabel)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[typeLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, typeLabel)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[zonesLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, zonesLabel)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[sceneLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, sceneLabel)]];
Seems like a better way to do this then set up a constraint for each label to the image view. I tried adding NSLayoutFormatAlignAllCenterX to the first constrain, but it sets them all center to the content view's center X, doesn't line the label's center X up with each other. NSLayoutFormatAlignAllBaseline gives an error and crash when used vertically.
I'll have to do this again for the data (Acres: 'value').
You're on the right track with NSLayoutFormatAlignAllCenterX. All you need to do differently is isolate V:[headerView]-[acresLabel] from the rest of the constraint, since you don't want headerView's CenterX to be aligned with the 5 labels'.
// NSDictionary* views ;
[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-[acresLabel]" options:0 metrics:nil views:views] ;
// Use any of the horizontal NSLayoutFormats (NSLayoutFormatAlignAllLeft, NSLayoutFormatAlignAllRight, NSLayoutFormatAlignAllLeading, NSLayoutFormatAlignAllTrailing, NSLayoutFormatAlignAllCenterX)
[NSLayoutConstraint constraintsWithVisualFormat:#"V:[acresLabel]-[addedLabel(==acresLabel)]-[typeLabel(==acresLabel)]-[zonesLabel(==acresLabel)]-[sceneLabel(==acresLabel)]-|" options:NSLayoutFormatAlignAllCenterX metrics:0 views:views] ;
[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[acresLabel]" options:0 metrics:nil views:views] ;

Resources