I want to implement custom UIView (from code) with dynamic height, based on content (similar to UILabel). I can do this by implementing intrinsicContentSize - and it seems to work correctly, but...
When I am adding my custom view to view controller on storyboard, I've got error (missing height constraint) - even when during launch everything seems to resize correctly.
When you add UILabel to storyboard you don't have to specify height, there are no errors.
How to achieve the same behavior for custom UIView (I want to use it in storyboard)?
If someone will need the solution:
I just found that there is "Intrinsic Size" property in Storyboard - you just need to set it to "Placeholder" and set some values just for Interface Builder...
i come to know that you are creating by programmatically.
try to use the following code and improve it in your requirement . Best of luck.
NSDictionary* views = #{#"view" : self.view};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[view]|" options:0 metrics:0 views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[view]|" options:0 metrics:0 views:views]];
Related
I am adding a UIView to a UITableViewCell using the code below
[cell.contentView addSubview:self.mTravelSearchView];
The travel search view appears in the cell. In the interface builder I have added correct constraints to self.mTravelSearchView so everything within this view renders correctly.
However I believe I need to programmatically add constraints so that the mTravelSearchView occupies the entire cell as at present it doesn't.
I have tried the below code, but the width of the view is wrong still and only uses a portion of the cell. What am I doing wrong?
[cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[travelSearch]|" options:0 metrics:nil views:#{#"travelSearch" : self.mTravelSearchView}]];
[cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[travelSearch]|" options:0 metrics:nil views:#{#"travelSearch" : self.mTravelSearchView}]];
I'm not really familiar with programmatically adding the constraints.
Nevermind, found that I needed this line
self.mTravelSearchView.translatesAutoresizingMaskIntoConstraints = NO;
I have some TableView using a basic or subtitle UITableViewCell and displaying an image/icon. The separator line is automatically indented and starts where the labels are displayed. So far so good. (see correct behavior)
Now I need a couple more labels and an image. Therefore, I created a custom TableViewCell with 4 labels. Without the image they work as expected. But when I add an image to the existing standard ImageView, the image is displayed, the separator line is indented but the custom labels are not. They overlay the image. (see wrong behavior)
Do I have to create a custom ImageView as well to get it working correctly and how is the separator line indented on that way or is there another possibility / state of the art to do something like that?
1. First off create an outlet of all the four custom elements like label and image view as :- lblOne, lblTwo, lblThree, imageView, respectively.
2. Then go to view Viewdidload and create a dictionary :-
NSDictionary *viewsDictionary = #{#" #"superview":self.view,
#"lblOne":self.lblOne,
#"lblTwo":self.lblTwo,
#"lblThree":self.lblThree,
#"imageView":self.imageView
};
3. Now add the Autolayout constraint programmatically :-
NSArray *lblOutletCenterConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[superView]-(<=1)-[lblOne]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:viewsDictionary];
[self.view addConstraints:lblOutletCenterConstraint];
NSArray *lblOutletCenterConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[superView]-(<=1)-[lblTwo]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:viewsDictionary];
[self.view addConstraints:lblOutletCenterConstraint];
NSArray *captionTopConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[lblOne]-25-[imageView]" options:0 metrics:nil views:viewsDictionary];
[self.view addConstraints:captionTopConstraint];
NSArray *captionTopConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[lblTwo]-25-[lblThree]" options:0 metrics:nil views:viewsDictionary];
[self.view addConstraints:captionTopConstraint];
4. Or you can do that by storyboard also.
I finally ended with the solution that I created an empty Interface Builder document, added a TableViewCell, put the Label and ImageView on it, set the constraints, connected everything to the corresponding *.swift file. Finish. I hoped to reuse the ImageView from the default TableViewCell but obviously that did not work correctly (or I was too stupid).
I'm trying resize a label dynamically according to text height. The height can vary from 0 to many lines in the UILabel. I've come up with a solution for this problem that works fine on iOS 8 but fails on iOS 7.1 which I'm trying to support as well.
Autolayout is not being used in this project and all constraints are done programatically.
The code is as follows:
//TableDelegate.m
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 85.0f;
}
//CustomTableViewCell.m
-(UILabel *)commentTextLabel
{
if(!_commentTextLabel)
{
_commentTextLabel = [UILabel new];
_commentTextLabel.numberOfLines = 0;
_commentTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
}
return _commentTextLabel;
}
-(void)setupViews
{
[self.contentView addSubview:self.profilePictureView];
[self.contentView addSubview:self.userName];
[self.contentView addSubview:self.timePublishedLabel];
[self.contentView addSubview:self.commentTextLabel];
[self.contentView addSubview:self.seeMoreButton];
self.backgroundColor = [UIColor salooteInputTextBg];
self.contentView.backgroundColor = [UIColor salooteInputTextBg];
NSDictionary *views = #
{
#"picture" : self.profilePictureView,
#"userName" : self.userName,
#"timePublished" : self.timePublishedLabel,
#"text" : self.commentTextLabel,
#"seeMore" : self.seeMoreButton
};
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[picture(38)]-5-[userName]-5-[timePublished]-5-|" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[picture]-5-[text]-5-|" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[seeMore]-5-|" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-5-[userName]-5-[text]-5-[seeMore]-5-|" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-5-[picture(38)]" options:0 metrics:nil views:views]];
}
-(void)updateConstraints
{
[super updateConstraints];
}
iOS 8 result (left) iOS 7.1 result (right)
I'm not setting any height constraint in my code for the UILabel but rather trying to let the constraints adjust the vertical height for me. If anyone has some input on how to make this work properly on iOS 7.1 I would really appreciate it.
Moving constraints into setupViews produces this: (iOS 7.1 top iOS 8 bottom)
It seems to me you're not adding vertical constraints to the commentTextLabel? You only have this:
//Comment text
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[picture]-5-[text]-0-|" options:0 metrics:nil views:views]];
Try setting a vertical constraint as well--it's likely that you're getting insufficient constraints errors and iOS 8 is guessing the height better than iOS 7. Also, if you're adding constraints to the views, you shouldn't have to call sizeToFit inside the getter.
Autolayout is not being used in this project and all constraints are done programatically.
You're still using Autolayout even if you're adding the constraints only programatically. :)
In response to edits
Your vertical height constraint is insufficient--you only specified the height of the commentTextLabel but not its y-coordinate. Remember that the main objective in Autolayout is to provide a complete set of constraints such that iOS can compute for a view's x, y, width, and height.
I think your constraints are screwed up overall. :) Try adding these rules to the content view instead (I just used 5 for any padding):
H:|-5-[picture(38)]-5-[username]-5-[timePublished]-5-|
H:[picture]-5-[text]-5-|
H:|-5-[seeMore]-5-|
V:|-5-[username]-5-[text]-5-[seeMore]-5-|
V:|-5-[picture(38)]
Also, add your constraints in setupViews--you should only have to add your constraints once and ONLY modify them in updateConstraints. I think updateConstraints is called every time layoutSubviews is called so your constraints keep getting added every time the cell's layout is refreshed.
In response to edits
Your label's word wrap style must be set, too. From inside the commentTextLabel, add
_commentTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
Always set that in conjunction to numberOfLines = 0 if you want a UILabel with a dynamic height.
You also need to right-align your seeMore label (it occupies the full width of the cell minus the padding) by setting that label's alignment property.
And try providing a bigger faux height for now--perhaps 150 or 200 instead of 85, just so we can see all the elements.
For the timePublished label, I forgot to indicate the following vertical constraint:
V:|-5-[timePublished]
I have found that the only way to support both iOS7 and iOS8 easily, is to do the height calculations for each cell yourself using off screen prototypes. The following is an excellent article on the issues. I could find no way to mix auto layout height calculation from iOS8 with manual height estimates for iOS7 in a single code base.
Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
The only issue I had with this method was when I used size classes to change the cell font sizes so I could have larger font on iPad etc... This issue is discussed here:
Offscreen UITableViewCells (for size calculations) not respecting size class?
I've got a UIView with a UILabel subview that has constraints defined like so:
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[_messageLabel]-50-|" options:0 metrics:nil views:views];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[_messageLabel]-0-|" options:0 metrics:nil views:views];
[self addConstraints:constraints];
In certain instances, the label is not big enough to show all the text, so it is truncated.
When I adjust the size of the UIView within an animation block, the label animates its change in size as appropriate. However, the re-drawing of the text within it kind of 'jumps' -- and fair enough, i wouldn't expect the label to animate a change in the internal drawing of its text.
Anyway, what I'd like to do is fade out this label and perhaps fade in a second to avoid this jerkiness.
My question: Is there a good callback on UIView as to when it will respond to an auto layout change? or is that simply done in layoutSubviews?
So I am having extreme difficulties in understanding how I can create these same constraints that the interface builder so nicely has created for me.
I have been reading the document on apple developer site and trying to follow it, but I can't seem to get these work. I am creating a custom view controller that adds a subview and creates those same constraints for that new view when it's pushed in.(The bottom constraint is where the new view is pushed, the top view is ALWAYS the same) I have written this following code but it doesn't seem to work properly(for example when I simulate in-call status bar, the views don't act like on the initial view where IB has created the constraints)
My code:
QVViewController * __weak vc1 = (QVViewController*)self.rootViewController2.parentViewController;
UIView *viewToBePushed = tempV.view;
UIView *topContainerView = self.rootViewController1.view;
id bottomLayoutGuide = tempV.bottomLayoutGuide;
[vc1.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewToBePushed]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(viewToBePushed)]];
[vc1.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[topContainerView]-0-[viewToBePushed]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(viewToBePushed,topContainerView)]];
[vc1.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-138-[viewToBePushed]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(viewToBePushed)]];
[vc1.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[viewToBePushed]|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(viewToBePushed)]];
[vc1.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[viewToBePushed]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(viewToBePushed)]];
[vc1.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[bottomLayoutGuide]-0-[viewToBePushed]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(viewToBePushed, bottomLayoutGuide)]];
Basically
viewToBePushed represents the bottom container in the picture
topContainerView represents the top container in the picture
vc1 is the view where those two container are
I hope I explained the situation clearly enough, if not, ask and I can try to elaborate. I would be really grateful for help as these constraint things are stealing my good night sleep and I very much would want to write easily maintainable code.
So can someone show me how to correctly create those constraints in code.
Given your setup, I think the bottom container view should have whatever constraints you need, but they don't ever need to be changed. When you switch to a new controller embedded in that container view, you can just set constraints to all sides of that container (after viewThatWasPushed is added as a subview)
[self.bottomContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[viewThatWasPushed]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewThatWasPushed)]];
[self.bottomContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[viewThatWasPushed]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewThatWasPushed)]];
self.bottomContainerView is an IBOutlet to theta bottom view.