Custom UITableViewCell with Image and Label - ios

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).

Related

add visual constraints to UITableViewCell so that the UIView occupies the entire cell

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;

Custom UIView with dynamic height on Storyboard

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]];

UIView with UILabel subview - responding to AutoLayout changes

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?

iOS Autolayout: How to move views when label text gets longer

I have a tableview cell with two labels and a small image.
If the labeltexts are short, all fits in one row like this:
.________________________________________.
| |
| [firstlabel] [img] [secondlabel] > |
|________________________________________|
However, if the labeltexts are getting longer, the image
and the second label should move to the second line:
.________________________________________.
| |
| [firstveryverylonglabel] > |
| [img] [secondverylonglabel] |
|________________________________________|
How would I do this with autolayout?
The first label is easy - just add constraints for left and top. Labels are always only one line heigh, and get truncated in the middle if the text gets way too long.
The image must always be in front of the second label (default space) horizontally, and both centered vertically. The image size should scale with the dynamic text font size (preferredFontForTextStyle:UIFontTextStyleBody) of the labels, so that if the user chooses large text the image also gets drawn larger.
The cell height should of course grow if two lines are needed.
Bonus Points if setting the necessary constraints would be possible in Interface Builder, but if not then I could set them with code in the init routine of the tableview cell.
My app should run under iOS 7 and later - no need for iOS 6. So I must compute the height in tableview:heightForCellAtIndexPath:, and will use a hidden cell to let Autolayout do its magic there.
I ended with setting constraints in code. I embedded the labels and the image in another view, then implemented -updateConstraints for the cell and the view.
In -tableView:heightForRowAtIndexPath:, I first let Autolayout make a first pass on the static hidden cell (just used for measuring) to set up the contentView by calling layoutIfNeeded, then force it to update the constraints by calling setNeedsUpdateConstraints followed by updateConstraintsIfNeeded, and finally measure the height of the cell with systemLayoutSizeFittingSize:UILayoutFittingCompressedSize.
In my view's updateConstraints method, I first try to arrange the cells side-by-side with
[self removeConstraints];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
#"V:|-margin-[first]-margin-|"
options:0 metrics:metrics views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
#"H:|-margin-[first]-[image]-[second]-margin-|"
options:NSLayoutFormatAlignAllCenterY metrics:metrics views:views]];
Then I call systemLayoutSizeFittingSize:UILayoutFittingCompressedSize on the view and compare the width to the maximum possible space inside the contentView, given its fixed horizontal start position. If it's too wide, I need to set a two-line constraint set:
[self removeConstraints];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
#"V:|-margin-[first]-[second]-margin-|"
options:0 metrics:metrics views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
#"H:|-margin-[first]-margin-|"
options:0 metrics:metrics views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
#"H:|-margin-[image]-[second]-margin-|"
options:NSLayoutFormatAlignAllCenterY metrics:metrics views:views]];
In the cell's updateConstraints method, I just call setNeedsUpdateConstraints on the view to make sure that the view is recalculated after the cell's size changed (e.g. when rotating portrait<=>landscape).
And that's it.

AutoLayout two labels within a TableViewCell?

I'm fairly new to iOS programming and probably don't understand the view hierarchy as well as I should and thus am failing to successfully get two labels within a custom table cell class I have created to autoresize properly. Namely the "translatesAutoresizingMaskIntoConstraints" property has me a little confused.
I am not using storyboards for this part of the code: I have a TableViewController where I create my own tableView in viewDidLoad. In cellForRowAtIndexPath I init my own TableViewCell implementation.
The problem I'm having is that when I set "setTranslatesAutoresizingMaskIntoConstraints" to NO for the table view and the UILabels I create then add my constraints, I get the following error:
"Terminating app due to uncaught exception `'NSInternalInconsistencyException',` reason: 'Auto Layout still required after executing `-layoutSubviews`. UITableView's implementation of `-layoutSubviews` needs to call super.'"
If I comment out the setTranslatesAutoresizingMaskIntoConstraints lines, my app runs however I get the following warning about the constraints:
"Unable to simultaneously satisfy constraints. Probably at least one
of the constraints in the following list is one you don't want. Try
this: (1) look at each constraint and try to figure out which you
don't expect; (2) find the code that added the unwanted constraint or
constraints and fix it. (Note: If you're seeing
NSAutoresizingMaskLayoutConstraints that you don't understand, refer
to the documentation for the UIView property
translatesAutoresizingMaskIntoConstraints)"
Essentially what I want to do is to enter code here have the two labels flush against each other and for them to resize based on orientation/device (I will be setting a background colour on them so want them to look 'continuous')
Can anyone help me out and explain what I am missing? Thanks in advance.
My code for adding the labels is:
self.nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 30.0f)];
self.nameLabel.textColor = [UIColor redColor];
self.nameLabel.font = [UIFont fontWithName:#"Helvetica Neue" size:12.0f];
self.nameLabel.backgroundColor = [UIColor brownColor];
[self.nameLabel setText:#"Test"];
// [self.nameLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.contentView addSubview:self.nameLabel];
...
NSDictionary *viewsDictionary =
NSDictionaryOfVariableBindings(nameLabel, summaryLabel);
NSArray *constraints =
[NSLayoutConstraint constraintsWithVisualFormat:#"|-[nameLabel][summaryLabel]-|"
options:0
metrics:nil
views:viewsDictionary];
I'm fairly new to ios programming and probably don't understand the
view hierarchy as well as I should and thus am failing to successfully
get two labels within a custom table cell class I have created to
autoresize properly. Namely the
"setTranslatesAutoresizingMaskIntoConstraints" property has me a
little confused.
Well, translatesAutoresizingMaskIntoConstraints is a property that is created by Apple to make the transition from Autoresizing (Spring and Struts) to Autolayout easier. Say, you had some AutoresizingMasks for your view and you just switched Autolayout ON without setting any constraints. Then your existing AutoresizingMasks will get converted into constraints which will hold the view in place. So, by default translatesAutoresizingMaskIntoConstraints property is set to be YES. However, when you start adding constraints, in 90% cases they will conflict with the constraints that got created by converting your AutoresizingMasks. So, it is better to turn it off by setting view.translatesAutoresizingMaskIntoConstraints = NO
In your code, the following might have been creating the problems:
The setting of Frame
You should not set frames to objects which you will be adding constraints to. It's a paradigm shift. When you think in Autolayout way, frames are but effects of setting right constraints who combinedly determine the frame of the view in question.
So, please remove the frame setting.
self.nameLabel = [[UILabel alloc] init]; will suffice.
Setting proper constraints
Your Code:
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(nameLabel, summaryLabel);
NSArray *constraints =
[NSLayoutConstraint constraintsWithVisualFormat:#"|-[nameLabel][summaryLabel]-|"
options:0
metrics:nil
views:viewsDictionary];
NameLabel
Now, the above constraints tells us the nameLabel should be horizontally (as you have not mentioned H: or V:) spaced "standard" distance (20px) from container, adjacent to the summaryLabel.
But what about its Y position and Width and Height?
So we need more constraints.
summaryLabel
Same is applicable for summaryLabel.
So, lets define them properly:
NSDictionary *viewsDictionary =
NSDictionaryOfVariableBindings(nameLabel, summaryLabel);
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[nameLabel(100)][summaryLabel]-|" options:0 metrics:nil views:viewsDictionary];
NSArray *constraints1 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[nameLabel(30)]" options:0 metrics:nil views:viewsDictionary];
NSArray *constraints2 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[summaryLabel]" options:0 metrics:nil views:viewsDictionary];
NSArray *constraints3 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[nameLabel(==summaryLabel)]" options:0 metrics:nil views:viewsDictionary];
[self.view addConstraints:constraints];
[self.view addConstraints:constraints1];
[self.view addConstraints:constraints2];
[self.view addConstraints:constraints3];
Now your views will look fine.
At any point of time, to check if your views are missing any constraints, pause the debugger and type the following in the console
po [[UIWindow keyWindow] _autolayoutTrace]
it will show which of your views are having AMBIGUOUS LAYOUT
Also, remember in Storyboard/IB if the constraints are showing as "orange" colour, you need more constraints to define the objects position. Once you have added all necessary constraints, the constraints colours turn to "blue"
First, are you adding constraints to self.contentView after creation?
Second, maybe your constraint set is insufficient for autolayout and it creates own constraints based on autoresizing mask. Try to add vertical constraints and width constraints for labels.

Resources