Xcode Table Cell Image Overlap - ios

I'm learning Objective C & working on an Instagram clone for a class assignment. Currently I have a problem with auto layout. Specifically, images & comments are overlapping on each other:
I believe the problem is in the auto layout:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.mediaImageView = [[UIImageView alloc] init];
self.usernameAndCaptionLabel = [[UILabel alloc] init];
self.usernameAndCaptionLabel.numberOfLines = 0;
self.commentLabel = [[UILabel alloc] init];
self.commentLabel.numberOfLines = 0;
for (UIView *view in #[self.mediaImageView, self.usernameAndCaptionLabel, self.commentLabel]) {
[self.contentView addSubview:view];
view.translatesAutoresizingMaskIntoConstraints = NO;
}
NSDictionary *viewDictionary = NSDictionaryOfVariableBindings(_mediaImageView, _usernameAndCaptionLabel, _commentLabel);
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_mediaImageView]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_usernameAndCaptionLabel]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_commentLabel]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_mediaImageView][_usernameAndCaptionLabel][_commentLabel]"
options:kNilOptions
metrics:nil
views:viewDictionary]];
self.imageHeightConstraint = [NSLayoutConstraint constraintWithItem:_mediaImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
self.usernameAndCaptionLabelHeightConstraint = [NSLayoutConstraint constraintWithItem:_usernameAndCaptionLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
self.commentLabelHeightConstraint = [NSLayoutConstraint constraintWithItem:_commentLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
[self.contentView addConstraints:#[self.imageHeightConstraint, self.usernameAndCaptionLabelHeightConstraint, self.commentLabelHeightConstraint]]; }
return self;
}
I've gone through the class tutorial several time and have researched iOS SDK Table Cell Overlapping but have not been able to find a suitable answer.
Here is the entire code:
#import "AppDelegate.h"
#import "UITableViewCell+BLCMediaTableViewCell.h"
#import "NSObject+BLCMedia.h"
#import "NSObject+BLCComment.h"
#import "NSObject+BLCUser.h"
//#implementation UITableViewCell (BLCMediaTableViewCell)
#interface BLCMediaTableViewCell() {
BLCMedia* _mediaItem;
}
#property (nonatomic, strong) UIImageView *mediaImageView;
#property (nonatomic, strong) UILabel *usernameAndCaptionLabel;
#property (nonatomic, strong) UILabel *commentLabel;
// Assignment: Added auto layout
#property (nonatomic, strong) NSLayoutConstraint *imageHeightConstraint;
#property (nonatomic, strong) NSLayoutConstraint *usernameAndCaptionLabelHeightConstraint;
#property (nonatomic, strong) NSLayoutConstraint *commentLabelHeightConstraint;
#end
static UIFont *lightFont;
static UIFont *boldFont;
static UIColor *usernameLabelGray;
static UIColor *commentLabelGray;
static UIColor *linkColor;
static NSParagraphStyle *paragraphStyle;
#implementation BLCMediaTableViewCell : UITableViewCell
- (void) layoutSubviews
{
[super layoutSubviews];
// Before layout, calculate the intrinsic size of the labels (the size they "want" to be), and add 20 to the height for some vertical padding.
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
self.imageView.frame = CGRectMake(self.imageView.frame.origin.x, self.imageView.frame.origin.y, 100, 100);
CGSize maxSize = CGSizeMake(CGRectGetWidth(self.bounds), CGFLOAT_MAX);
CGSize usernameLabelSize = [self.usernameAndCaptionLabel sizeThatFits:maxSize];
CGSize commentLabelSize = [self.commentLabel sizeThatFits:maxSize];
self.usernameAndCaptionLabelHeightConstraint.constant = usernameLabelSize.height + 20;
self.commentLabelHeightConstraint.constant = commentLabelSize.height + 20;
// Hide the line between cells
self.separatorInset = UIEdgeInsetsMake(0, 0, 0, CGRectGetWidth(self.bounds));
}
+ (void)load {
lightFont = [UIFont fontWithName:#"HelveticaNeue-Thin" size:11];
boldFont = [UIFont fontWithName:#"HelveticaNeue-Bold" size:11];
usernameLabelGray = [UIColor colorWithRed:0.933 green:0.933 blue:0.933 alpha:1]; /*#eeeeee*/
commentLabelGray = [UIColor colorWithRed:0.898 green:0.898 blue:0.898 alpha:1]; /*#e5e5e5*/
linkColor = [UIColor colorWithRed:0.345 green:0.314 blue:0.427 alpha:1]; /*#58506d*/
NSMutableParagraphStyle *mutableParagraphStyle = [[NSMutableParagraphStyle alloc] init];
mutableParagraphStyle.headIndent = 20.0;
mutableParagraphStyle.firstLineHeadIndent = 20.0;
mutableParagraphStyle.tailIndent = -20.0;
mutableParagraphStyle.paragraphSpacingBefore = 5;
paragraphStyle = mutableParagraphStyle;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.mediaImageView = [[UIImageView alloc] init];
self.usernameAndCaptionLabel = [[UILabel alloc] init];
self.usernameAndCaptionLabel.numberOfLines = 0;
self.commentLabel = [[UILabel alloc] init];
self.commentLabel.numberOfLines = 0;
for (UIView *view in #[self.mediaImageView, self.usernameAndCaptionLabel, self.commentLabel]) {
[self.contentView addSubview:view];
view.translatesAutoresizingMaskIntoConstraints = NO;
}
NSDictionary *viewDictionary = NSDictionaryOfVariableBindings(_mediaImageView, _usernameAndCaptionLabel, _commentLabel);
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_mediaImageView]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_usernameAndCaptionLabel]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_commentLabel]|" options:kNilOptions metrics:nil views:viewDictionary]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_mediaImageView][_usernameAndCaptionLabel][_commentLabel]"
options:kNilOptions
metrics:nil
views:viewDictionary]];
self.imageHeightConstraint = [NSLayoutConstraint constraintWithItem:_mediaImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
self.usernameAndCaptionLabelHeightConstraint = [NSLayoutConstraint constraintWithItem:_usernameAndCaptionLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
self.commentLabelHeightConstraint = [NSLayoutConstraint constraintWithItem:_commentLabel
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:100];
[self.contentView addConstraints:#[self.imageHeightConstraint, self.usernameAndCaptionLabelHeightConstraint, self.commentLabelHeightConstraint]]; }
return self;
}
- (NSAttributedString *) usernameAndCaptionString {
CGFloat usernameFontSize = 15;
// Make a string that says "username caption text"
NSString *baseString = [NSString stringWithFormat:#"%# %#", self.mediaItem.user.userName, self.mediaItem.caption];
// Make an attributed string, with the "username" bold
NSMutableAttributedString *mutableUsernameAndCaptionString = [[NSMutableAttributedString alloc] initWithString:baseString attributes:#{NSFontAttributeName : [lightFont fontWithSize:usernameFontSize], NSParagraphStyleAttributeName : paragraphStyle}];
NSRange usernameRange = [baseString rangeOfString:self.mediaItem.user.userName];
[mutableUsernameAndCaptionString addAttribute:NSFontAttributeName value:[boldFont fontWithSize:usernameFontSize] range:usernameRange];
[mutableUsernameAndCaptionString addAttribute:NSForegroundColorAttributeName value:linkColor range:usernameRange];
return mutableUsernameAndCaptionString;
}
- (void) setMediaItem:(BLCMedia *)mediaItem {
_mediaItem = mediaItem;
self.mediaImageView.image = _mediaItem.image;
self.usernameAndCaptionLabel.attributedText = [self usernameAndCaptionString];
self.commentLabel.attributedText = [self commentString];
self.imageHeightConstraint.constant = self.mediaItem.image.size.height / self.mediaItem.image.size.width * CGRectGetWidth(self.contentView.bounds);
}
//Added
- (CGSize) sizeOfString:(NSAttributedString *)string {
CGSize maxSize = CGSizeMake(CGRectGetWidth(self.contentView.bounds) - 40, 0.0);
CGRect sizeRect = [string boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];
sizeRect.size.height += 20;
sizeRect = CGRectIntegral(sizeRect);
return sizeRect.size;
}
- (NSAttributedString *) commentString {
NSMutableAttributedString *commentString = [[NSMutableAttributedString alloc] init];
for (BLCComment *comment in self.mediaItem.comments) {
// Make a string that says "username comment text" followed by a line break
NSString *baseString = [NSString stringWithFormat:#"%# %#\n", comment.from.userName, comment.text];
// Make an attributed string, with the "username" bold
NSMutableAttributedString *oneCommentString = [[NSMutableAttributedString alloc] initWithString:baseString attributes:#{NSFontAttributeName : lightFont, NSParagraphStyleAttributeName : paragraphStyle}];
NSRange usernameRange = [baseString rangeOfString:comment.from.userName];
[oneCommentString addAttribute:NSFontAttributeName value:boldFont range:usernameRange];
[oneCommentString addAttribute:NSForegroundColorAttributeName value:linkColor range:usernameRange];
[commentString appendAttributedString:oneCommentString];
}
return commentString;
}
+ (CGFloat) heightForMediaItem:(BLCMedia *)mediaItem width:(CGFloat)width {
// Make a cell
BLCMediaTableViewCell *layoutCell = [[BLCMediaTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"layoutCell"];
[layoutCell setNeedsLayout];
[layoutCell layoutIfNeeded];
// Get the actual height required for the cell
return CGRectGetMaxY(layoutCell.commentLabel.frame);
}
#end

So I figured out what I was doing wrong. My layoutSubViews were incorrect. I've included a screenshot of the bad version & the corrected version in my public Dropbox. I hope this can help someone else later down the road.
The original code was:
- (void) layoutSubviews
{
[super layoutSubviews];
// Before layout, calculate the intrinsic size of the labels (the size they "want" to be), and add 20 to the height for some vertical padding.
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
self.imageView.frame = CGRectMake(self.imageView.frame.origin.x, self.imageView.frame.origin.y, 100, 100);
CGSize maxSize = CGSizeMake(CGRectGetWidth(self.bounds), CGFLOAT_MAX);
CGSize usernameLabelSize = [self.usernameAndCaptionLabel sizeThatFits:maxSize];
CGSize commentLabelSize = [self.commentLabel sizeThatFits:maxSize];
self.usernameAndCaptionLabelHeightConstraint.constant = usernameLabelSize.height + 20;
self.commentLabelHeightConstraint.constant = commentLabelSize.height + 20;
// Hide the line between cells
self.separatorInset = UIEdgeInsetsMake(0, 0, 0, CGRectGetWidth(self.bounds));
}
It should have read:
- (void) layoutSubviews
{
[super layoutSubviews];
if (self.mediaItem == nil){
return;
}
// Before layout, calculate the intrinsic size of the labels (the size they "want" to be), and add 20 to the height for some vertical padding.
CGSize maxSize = CGSizeMake(CGRectGetWidth(self.bounds), CGFLOAT_MAX);
CGSize usernameLabelSize = [self.usernameAndCaptionLabel sizeThatFits:maxSize];
CGSize commentLabelSize = [self.commentLabel sizeThatFits:maxSize];
self.usernameAndCaptionLabelHeightConstraint.constant = usernameLabelSize.height + 20;
self.commentLabelHeightConstraint.constant = commentLabelSize.height + 20;
if (_mediaItem.image)
{
self.imageHeightConstraint.constant = self.mediaItem.image.size.height / self.mediaItem.image.size.width * CGRectGetWidth(self.contentView.bounds);
}
else
{
self.imageHeightConstraint.constant = 100;
}
//Hide the line between cells
self.separatorInset = UIEdgeInsetsMake(0, 0, 0, CGRectGetWidth(self.bounds));
}

Related

Methods for datasource are not called for this custom view

I would like to implement this sort of thing :
1- So first, I have implemented this view : UnitSliderView :
using this code :
#import "UnitSliderView.h"
#implementation UnitSliderView
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
//initialization
self.backgroundColor = [UIColor grayColor];
[self initViews];
[self initConstraints];
}
return self;
}
-(void)initViews
{
_leftLabel = [[UILabel alloc] init];
_leftLabel.textColor = [UIColor whiteColor];
//self.leftLabel.text = #"John";
[self addSubview:_leftLabel];
_rightLabel = [[UILabel alloc] init];
_rightLabel.textColor = [UIColor whiteColor];
//self.rightLabel.text = #"20%";
[self addSubview:self.rightLabel];
_slider = [[UISlider alloc] init];
_slider.value = 0.6;
[self addSubview:_slider];
}
-(void)initConstraints
{
self.rightLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.leftLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.slider.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"leftLabel": self.leftLabel,
#"slider": self.slider,
#"rightLabel": self.rightLabel,
};
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[leftLabel(==90)]-5-[slider(==120)]-[rightLabel(==50)]-|" options:0 metrics:nil views:views]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.slider attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.leftLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.rightLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
}
#end
2- Then, I have created this view, named MultiSliderView, which use the precedent View (UnitSliderView):
#import "MultiSliderView.h"
#import "UnitSliderView.h"
static const int kUnitsCount = 3;
#implementation MultiSliderView
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
//initialization
self.backgroundColor = [UIColor clearColor];
[self initViews];
}
return self;
}
- (void)initViews {
float totalHeight = self.frame.size.height;
float spacingRatio = 0.1;
float heightPerUnit = totalHeight/(kUnitsCount+spacingRatio*(kUnitsCount));
for (int i = 0; i < kUnitsCount; i++)
{
double percentage = [self.dataSource valueForSliderAtIndex:i];
NSString *leftString = [self.dataSource stringForLeftLabelAtIndex:i];
NSString *rightString = [self.dataSource stringForRightLabelAtIndex:i];
UnitSliderView *unit = [[UnitSliderView alloc] initWithFrame:CGRectMake(0, i*heightPerUnit + (i)*heightPerUnit*spacingRatio, self.frame.size.width, heightPerUnit)];
unit.slider.value = percentage;
unit.leftLabel.text = leftString;
unit.rightLabel.text = rightString;
[self addSubview:unit];
}
}
#end
3 - problem : when I init a MultiSlidersView in a viewController, the datasource methods that I have implemented in this same view controller are not called, thus the labels are not shown, and the slider values are 0.
I think there some of my code is not in the right place, but I can't find how to do it differently.
You should define the dataSource of the created class before you call the init function. You should define a method initWithFrame:(CGRect)frame andDataSource:(id <MultiSliderViewDataSource> ) dataSource and use it to initialize your view.
I assume you want to get an action called whenever the slide value changes. Since you implemented everything in code, you can do this in code using e.g.
[youSlider addTarget:self action:#selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];

IOS - UILabel dynamic height in UIView using AutoLayout

I have a UITableView and custom UITableViewCell. I have added AutoLayout inside the cell and in this cell i have a UILabel that needs to dynamically change its height and then i have a UIView that contains other subviews including this UILabel that needs its height dynamically changed. I get no errors but this is the custom UITableViewCell:
The dynamic text should force the bottom UIView after the dynamic text. But as you can see the dynamic text passes the bottom UIView.
#import "PostTableViewCell.h"
#implementation PostTableViewCell
#synthesize main;
#synthesize top;
#synthesize center;
#synthesize bottom;
#synthesize labelMessage;
#synthesize labelCat;
#synthesize labelUser;
#synthesize labelDate;
#synthesize imageviewThreadImage;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self.contentView setTranslatesAutoresizingMaskIntoConstraints:NO];
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
main = [UIView new];
[self.contentView addSubview:main];
main.translatesAutoresizingMaskIntoConstraints = NO;
//[main sizeToFit];
main.backgroundColor = [UIColor whiteColor];
top = [UIView new];
[main addSubview:top];
top.translatesAutoresizingMaskIntoConstraints = NO;
//[top sizeToFit];
top.backgroundColor = [UIColor whiteColor];
labelUser = [UILabel new];
[top addSubview:labelUser];
labelUser.translatesAutoresizingMaskIntoConstraints = NO;
//[labelUser sizeToFit];
[labelUser setFont:[UIFont systemFontOfSize:14]];
labelUser.textColor = [UIColor colorWithRed:(114.0/255.0) green:(114.0/255.0) blue:(114.0/255.0) alpha:1.0];
labelDate = [UILabel new];
[top addSubview:labelDate];
labelDate.translatesAutoresizingMaskIntoConstraints = NO;
[labelDate sizeToFit];
[labelDate setFont:[UIFont systemFontOfSize:14]];
labelDate.textColor = [UIColor colorWithRed:(114.0/255.0) green:(114.0/255.0) blue:(114.0/255.0) alpha:1.0];
center = [UIView new];
[main addSubview:center];
center.translatesAutoresizingMaskIntoConstraints = NO;
[center sizeToFit];
center.backgroundColor = [UIColor whiteColor];
imageviewThreadImage = [UIImageView new];
[center addSubview:imageviewThreadImage];
imageviewThreadImage.translatesAutoresizingMaskIntoConstraints = NO;
imageviewThreadImage.backgroundColor = [UIColor colorWithRed:(207.0/255.0) green:(215.0/255.0) blue:(248.0/255.0) alpha:1.0];
labelMessage = [UILabel new];
[center addSubview:labelMessage];
labelMessage.translatesAutoresizingMaskIntoConstraints = NO;
[labelMessage sizeToFit];
[labelMessage setFont:[UIFont systemFontOfSize:14]];
labelMessage.preferredMaxLayoutWidth = screenWidth - 10 - 36;
labelMessage.lineBreakMode = NSLineBreakByWordWrapping;
labelMessage.numberOfLines = 0;
labelMessage.textColor = [UIColor lightGrayColor];
bottom = [UIView new];
[main addSubview:bottom];
bottom.translatesAutoresizingMaskIntoConstraints = NO;
[bottom sizeToFit];
labelCat = [UILabel new];
[bottom addSubview:labelCat];
labelCat.translatesAutoresizingMaskIntoConstraints = NO;
[labelCat sizeToFit];
[labelCat setFont:[UIFont systemFontOfSize:12]];
labelCat.textColor = [UIColor colorWithRed:(58.0/255.0) green:(82.0/255.0) blue:(207.0/255.0) alpha:1.0];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Make sure the contentView does a layout pass here so that its subviews have their frames set, which we
// need to use to set the preferredMaxLayoutWidth below.
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
// Set the preferredMaxLayoutWidth of the mutli-line bodyLabel based on the evaluated width of the label's frame,
// as this will allow the text to wrap correctly, and as a result allow the label to take on the correct height.
self.labelMessage.preferredMaxLayoutWidth = CGRectGetWidth(self.labelMessage.frame);
}
- (void)updateConstraints {
[super updateConstraints];
if (self.didSetupConstraints) return;
NSDictionary *viewsDictionary7 = #{#"main":main};
NSArray *constraint_H37 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[main]|"
options:0
metrics:nil
views:viewsDictionary7];
NSArray *constraint_V37 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[main]|"
options:0
metrics:nil
views:viewsDictionary7];
[self.contentView addConstraints:constraint_H37];
[self.contentView addConstraints:constraint_V37];
NSDictionary *viewsDictionary3 = #{#"top":top,#"center":center,#"bottom":bottom,#"labelMessage":labelMessage};
NSArray *constraint_H3 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-5-[top]-5-[center]-5-[bottom]-10-|"
options:0
metrics:nil
views:viewsDictionary3];
NSArray *constraint_H33 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[top]|"
options:0
metrics:nil
views:viewsDictionary3];
NSArray *constraint_H333 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[center]|"
options:0
metrics:nil
views:viewsDictionary3];
NSArray *constraint_H3335657 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[bottom]|"
options:0
metrics:nil
views:viewsDictionary3];
NSDictionary *viewsDictionary4 = #{#"labelUser":labelUser,#"labelDate":labelDate};
NSArray *constraint_H4 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[labelUser]|"
options:0
metrics:nil
views:viewsDictionary4];
NSDictionary *viewsDictionary45 = #{#"labelDate":labelDate};
NSArray *constraint_H4555 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[labelDate]|"
options:0
metrics:nil
views:viewsDictionary45];
NSArray *constraint_H44 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[labelUser]-20-[labelDate]-5-|"
options:0
metrics:nil
views:viewsDictionary4];
NSDictionary *viewsDictionary48 = #{#"labelMessage":labelMessage,#"imageviewThreadImage":imageviewThreadImage};
NSArray *constraint_H48 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[labelMessage]"
options:0
metrics:nil
views:viewsDictionary48];
NSArray *constraint_H48342 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-8-[imageviewThreadImage(36)]|"
options:0
metrics:nil
views:viewsDictionary48];
NSArray *constraint_H448 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[imageviewThreadImage(36)]-5-[labelMessage]-5-|"
options:0
metrics:nil
views:viewsDictionary48];
NSDictionary *viewsDictionary488 = #{#"labelCat":labelCat};
NSArray *constraint_H488 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-5-[labelCat]|"
options:0
metrics:nil
views:viewsDictionary488];
NSArray *constraint_H4488 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[labelCat]"
options:0
metrics:nil
views:viewsDictionary488];
[main addConstraints:constraint_H3];
////[main addConstraints:constraint_H33];
[main addConstraints:constraint_H333];
[top addConstraints:constraint_H4];
[top addConstraints:constraint_H44];
[center addConstraints:constraint_H48];
[center addConstraints:constraint_H448];
[top addConstraints:constraint_H4555];
[main addConstraints:constraint_H3335657];
[main addConstraints:constraint_H488];
[main addConstraints:constraint_H48342];
[main addConstraints:constraint_H4488];
self.didSetupConstraints = YES;
}
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
This is the result i get:
Here is your answer redoc01
- (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Get table dat
static NSString *CellIdentifier = #"CustomCell";
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
//Create Cell
NSArray *nib;
nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell = (UITableViewCell *) [nib objectAtIndex:0];
}
if(indexPath.section == 0) {
UILabel *dateLable = (UILabel *) [cell.contentView viewWithTag:CELL_DATE_LABLE];
dateLable.text = _string3;
[dateLable layoutIfNeeded];
return dateLable.frame.size.height;
}
}
Let me know your feedback..
I solved it by changing the AutoLayout, this is the modified UITableViewCell that makes it work with AutoLayout:
#import "PostTableViewCell.h"
#implementation PostTableViewCell
#synthesize main;
#synthesize top;
#synthesize center;
#synthesize centerLeft;
#synthesize centerRight;
#synthesize bottom;
#synthesize labelMessage;
#synthesize labelCat;
#synthesize labelUser;
#synthesize labelDate;
#synthesize imageviewThreadImage;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self.contentView setTranslatesAutoresizingMaskIntoConstraints:NO];
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
main = [UIView new];
//[self.contentView addSubview:main];
main.translatesAutoresizingMaskIntoConstraints = NO;
[main sizeToFit];
main.backgroundColor = [UIColor whiteColor];
top = [UIView new];
[self.contentView addSubview:top];
top.translatesAutoresizingMaskIntoConstraints = NO;
[top sizeToFit];
top.backgroundColor = [UIColor whiteColor];
labelUser = [UILabel new];
[top addSubview:labelUser];
labelUser.translatesAutoresizingMaskIntoConstraints = NO;
[labelUser sizeToFit];
[labelUser setFont:[UIFont systemFontOfSize:14]];
labelUser.textColor = [UIColor colorWithRed:(114.0/255.0) green:(114.0/255.0) blue:(114.0/255.0) alpha:1.0];
labelDate = [UILabel new];
[top addSubview:labelDate];
labelDate.translatesAutoresizingMaskIntoConstraints = NO;
[labelDate sizeToFit];
[labelDate setFont:[UIFont systemFontOfSize:14]];
labelDate.textColor = [UIColor colorWithRed:(114.0/255.0) green:(114.0/255.0) blue:(114.0/255.0) alpha:1.0];
center = [UIView new];
[self.contentView addSubview:center];
center.translatesAutoresizingMaskIntoConstraints = NO;
[center sizeToFit];
center.backgroundColor = [UIColor whiteColor];
imageviewThreadImage = [UIImageView new];
[center addSubview:imageviewThreadImage];
imageviewThreadImage.translatesAutoresizingMaskIntoConstraints = NO;
imageviewThreadImage.backgroundColor = [UIColor colorWithRed:(207.0/255.0) green:(215.0/255.0) blue:(248.0/255.0) alpha:1.0];
[imageviewThreadImage sizeToFit];
labelMessage = [UILabel new];
[center addSubview:labelMessage];
labelMessage.translatesAutoresizingMaskIntoConstraints = NO;
[labelMessage sizeToFit];
[labelMessage setFont:[UIFont systemFontOfSize:14]];
labelMessage.preferredMaxLayoutWidth = screenWidth - 10 - 36;
labelMessage.lineBreakMode = UILineBreakModeWordWrap;
labelMessage.numberOfLines = 0;
labelMessage.textColor = [UIColor lightGrayColor];
//labelMessage.lineBreakMode = UILineBreakModeWordWrap;
bottom = [UIView new];
[self.contentView addSubview:bottom];
bottom.translatesAutoresizingMaskIntoConstraints = NO;
[bottom sizeToFit];
labelCat = [UILabel new];
[bottom addSubview:labelCat];
labelCat.translatesAutoresizingMaskIntoConstraints = NO;
[labelCat sizeToFit];
[labelCat setFont:[UIFont systemFontOfSize:12]];
labelCat.textColor = [UIColor colorWithRed:(58.0/255.0) green:(82.0/255.0) blue:(207.0/255.0) alpha:1.0];
labelCat.lineBreakMode = UILineBreakModeWordWrap;
labelCat.numberOfLines = 0;
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Make sure the contentView does a layout pass here so that its subviews have their frames set, which we
// need to use to set the preferredMaxLayoutWidth below.
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
// Set the preferredMaxLayoutWidth of the mutli-line bodyLabel based on the evaluated width of the label's frame,
// as this will allow the text to wrap correctly, and as a result allow the label to take on the correct height.
self.labelMessage.preferredMaxLayoutWidth = CGRectGetWidth(self.labelMessage.frame);
}
- (void)updateConstraints {
[super updateConstraints];
if (self.didSetupConstraints) return;
/**NSDictionary *viewsDictionary7 = #{#"main":main};
NSArray *constraint_H37 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[main]|"
options:0
metrics:nil
views:viewsDictionary7];
NSArray *constraint_V37 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[main]|"
options:0
metrics:nil
views:viewsDictionary7];
[self.contentView addConstraints:constraint_H37];
[self.contentView addConstraints:constraint_V37];**/
NSString *text = labelMessage.text;
NSDictionary *viewsDictionary3 = #{#"top":top,#"center":center,#"bottom":bottom};
NSArray *constraint_H3 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-10-[top]-5-[center(>=50)]-5-[bottom]-10-|"
options:0
metrics:nil
views:viewsDictionary3];
NSArray *constraint_H33 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[top]|"
options:0
metrics:nil
views:viewsDictionary3];
NSArray *constraint_H333 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[center]|"
options:0
metrics:nil
views:viewsDictionary3];
NSArray *constraint_H3335657 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[bottom]|"
options:0
metrics:nil
views:viewsDictionary3];
NSDictionary *viewsDictionary4 = #{#"labelUser":labelUser,#"labelDate":labelDate};
NSArray *constraint_H4 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[labelUser]|"
options:0
metrics:nil
views:viewsDictionary4];
NSDictionary *viewsDictionary45 = #{#"labelDate":labelDate};
NSArray *constraint_H4555 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[labelDate]|"
options:0
metrics:nil
views:viewsDictionary45];
NSArray *constraint_H44 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[labelUser]-20-[labelDate]-5-|"
options:0
metrics:nil
views:viewsDictionary4];
NSDictionary *viewsDictionary48 = #{#"labelMessage":labelMessage,#"imageviewThreadImage":imageviewThreadImage};
NSArray *constraint_H48 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-5-[labelMessage]|"
options:0
metrics:nil
views:viewsDictionary48];
NSArray *constraint_H48342 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-8-[imageviewThreadImage(36)]"
options:0
metrics:nil
views:viewsDictionary48];
NSArray *constraint_H448345fgdfg = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[imageviewThreadImage(36)]-5-[labelMessage]-5-|"
options:0
metrics:nil
views:viewsDictionary48];
/**NSArray *constraint_H448 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[labelMessage]-5-|"
options:0
metrics:nil
views:viewsDictionary48];**/
NSDictionary *viewsDictionary488 = #{#"labelCat":labelCat};
NSArray *constraint_H488 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[labelCat]|"
options:0
metrics:nil
views:viewsDictionary488];
NSArray *constraint_H4488 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[labelCat]"
options:0
metrics:nil
views:viewsDictionary488];
[self.contentView addConstraints:constraint_H3];
[self.contentView addConstraints:constraint_H33];
[self.contentView addConstraints:constraint_H333];
[self.contentView addConstraints:constraint_H4];
[self.contentView addConstraints:constraint_H44];
[self.contentView addConstraints:constraint_H48];
//[self.contentView addConstraints:constraint_H448];
[self.contentView addConstraints:constraint_H4555];
[self.contentView addConstraints:constraint_H3335657];
[self.contentView addConstraints:constraint_H488];
[self.contentView addConstraints:constraint_H48342];
[self.contentView addConstraints:constraint_H4488];
[self.contentView addConstraints:constraint_H448345fgdfg];
self.didSetupConstraints = YES;
}
- (CGFloat)heightForText:(NSString *)bodyText
{
UIFont *cellFont = [UIFont systemFontOfSize:17];
CGSize constraintSize = CGSizeMake(300, MAXFLOAT);
CGSize labelSize = [bodyText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = labelSize.height + 10;
return height;
}
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
In iOS 8 you can use the delegate function to calculate the cell size as such:
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
Make sure that you have bottom constraint between the label to the bottom of the contentView and you are done.
Please note it will work only on iOS 8.

Layout of custom UITableViewCell using Autolayout programmatically

I have a custom UITableViewCell that works great on iPhone 5s, however since this projected started we now have to update it to support iPhone 6 en iPhone 6 Plus as well.
I've solved most of these upgrade issues using Autolayout in my .xib files. This Cell however does not have a .xib so I Have to do everything programmatically. For clarity I've temporarily drawn a border around my problematic label
This is how it looks on iPhone 5S
This is how it looks on iPhone 6
These tableviews are expandable/collapsable. In the screenshot you see it expanded.
This is the relevant code:
#import "LotsDetailTableViewCell.h"
#import "MSCellAccessory.h"
#interface LotsDetailTableViewCell ()
#property (nonatomic, strong) NSArray *data;
#property (nonatomic, strong) UIView *detailView;
#end
const float LABEL_HEIGHT = 22.0f;
#implementation LotsDetailTableViewCell
- (id)initWithData:(NSArray *)data reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
if (self) {
self.data = data;
[self setupDetailView];
self.textLabel.textColor = RGB(39, 143, 191);
self.textLabel.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:16.0];
self.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.clipsToBounds = true;
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.textLabel.frame = CGRectMake(self.textLabel.frame.origin.x,
self.textLabel.frame.origin.y,
self.textLabel.frame.size.width,
43.5f);
self.accessoryView.frame = CGRectMake(self.accessoryView.frame.origin.x, 6, 32, 32);
}
#pragma mark Detail View
- (void)setupDetailView
{
self.detailView = [[UIView alloc] init];
UILabel *previousLabel;
for (NSObject *detail in self.data) {
CGFloat frameY;
NSString *keyText;
NSString *valueText;
if([detail isKindOfClass:[NSString class]]){
keyText = #"";
valueText = (NSString *)detail;
} else if([detail isKindOfClass:[NSDictionary class]]){
keyText = ((NSDictionary *)detail)[#"key"];
valueText = [(NSDictionary *)detail objectForKey:#"value"];
}
if (previousLabel) {
frameY = previousLabel.frame.origin.y+previousLabel.frame.size.height;
} else {
frameY = self.frame.origin.y+44.0f+[self.data indexOfObject:detail]*LABEL_HEIGHT;
}
UILabel *keyLabel = [[UILabel alloc] initWithFrame:
CGRectMake(self.frame.size.width*.05, frameY, self.frame.size.width*.45, [self heightForValueLabel:valueText])
];
UILabel *valueLabel = [[UILabel alloc] initWithFrame:
CGRectMake(self.frame.size.width*.5, frameY, self.frame.size.width*.45, [self heightForValueLabel:valueText])
];
valueLabel.lineBreakMode = NSLineBreakByWordWrapping;
valueLabel.numberOfLines = 0;
keyLabel.lineBreakMode = NSLineBreakByWordWrapping;
keyLabel.numberOfLines = 0;
valueLabel.textAlignment = NSTextAlignmentRight;
keyLabel.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:12.0];
valueLabel.font = [UIFont fontWithName:#"HelveticaNeue-Bold" size:12.0];
keyLabel.textColor = RGB(119, 119, 119);
valueLabel.textColor = RGB(39, 143, 191);
keyLabel.text = keyText;
valueLabel.text = valueText;
valueLabel.layer.borderColor = [RGB(178, 178, 178) CGColor];
valueLabel.layer.borderWidth = 1.0f;
[self.detailView addSubview:keyLabel];
[self.detailView addSubview:valueLabel];
previousLabel = valueLabel;
}
[self addSubview:self.detailView];
}
- (CGFloat)heightForValueLabel:(NSString *)text
{
return [[self class] heightForValueLabel:text width:self.frame.size.width*.5];
}
+ (CGFloat)heightForValueLabel:(NSString *)text width:(CGFloat)width
{
CGSize constrainedSize = CGSizeMake(width, CGFLOAT_MAX);
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"HelveticaNeue-Bold" size:12.0], NSFontAttributeName,
nil];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:text attributes:attributesDictionary];
CGRect requiredHeight = [string boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];
return requiredHeight.size.height+5.0;
}
+ (CGFloat)heightForData:(NSArray*)data width:(CGFloat)width
{
CGFloat height = 0.0;
for (NSObject *detail in data) {
NSString *valueText;
if([detail isKindOfClass:[NSString class]]){
valueText = (NSString *)detail;
} else if([detail isKindOfClass:[NSDictionary class]]){
valueText = ((NSDictionary *)detail)[#"value"];
}
height = height + [self heightForValueLabel:valueText width:width];
}
return height;
}
#end
Most of the relevant drawing is performed in the setupDetailView method.
What I want: I want the label to be aligned to the right hand side of the tableviewcell to make best use of the available space.
What I tried: I've tried adding a NSLayoutConstraint programmatically in the setupDetailView using the following co
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:valueLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:1.0];
[valueLabel addConstraint:constraint];
[self needsUpdateConstraints];
but this has lead to run-time crashes.
If my problem can be easily solved without Autolayout I'm not opposed to that.
Edit: If I try to add the constraint, this is how it blows up:
2015-03-25 14:19:04.047 App[35277:10763464] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7faf5049a630 UILabel:0x7faf50499a50'8050'.trailing == LotsDetailTableViewCell:0x7faf50494840'LotDetailInfoCell'.right + 1>
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2015-03-25 14:19:04.048 App[35277:10763464] View hierarchy unprepared for constraint.
Constraint: <NSLayoutConstraint:0x7faf5049a630 UILabel:0x7faf50499a50'8050'.trailing == LotsDetailTableViewCell:0x7faf50494840'LotDetailInfoCell'.right + 1>
Container hierarchy:
<LotsDetailTableViewCell: 0x7faf50494840; baseClass = UITableViewCell; frame = (0 0; 320 44); layer = <CALayer: 0x7faf50494c50>>
| <UITableViewCellContentView: 0x7faf5049c070; frame = (0 0; 320 44); gestureRecognizers = <NSArray: 0x7faf504a2530>; layer = <CALayer: 0x7faf50455b60>>
View not found in container hierarchy: <UILabel: 0x7faf50499a50; frame = (156 44; 144 19.304); text = '8050'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7faf50499870>>
That view's superview: NO SUPERVIEW
2015-03-25 14:19:04.058 App[35277:10763464] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal. constraint:<NSLayoutConstraint:0x7faf5049a630 UILabel:0x7faf50499a50'8050'.trailing == LotsDetailTableViewCell:0x7faf50494840'LotDetailInfoCell'.right + 1> view:<LotsDetailTableViewCell: 0x7faf50494840; baseClass = UITableViewCell; frame = (0 0; 320 44); layer = <CALayer: 0x7faf50494c50>>'
Give leftConstarint to your label, after adding it as subView.
[_label setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:_label
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:[_label superview]
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:10];
[_label addConstraint:leftConstraint];
[_label superview] must be your [self view]. //Might be.
Hope, it helps. :)
When adding constraints between subview and superview, you have to add them to the superview:
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:valueLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:1.0];
[self addConstraint:constraint];
[self needsUpdateConstraints];

uitableview drag down outside screen

I'm basically trying to achieve this effect: http://youtu.be/VBW2i0P11iI
The tableview is a basic one that's pinned to it's superview with autolayout. The view underneath is added with the classic insertSubview:belowSubview: / addChildViewController combo.
I've tried a couple of approaches. What I have now is:
if (scrollOffset >= -scrollView.contentInset.top) {
self.resultsTableViewContainerTopConstraint.constant = 0;
} else {
self.resultsTableViewContainerTopConstraint.constant = MAX(self.resultsTableViewContainerTopConstraint.constant, self.resultsTableViewContainerTopConstraint.constant - scrollDiff);
}
}
So I'm basically changing the top constraint based on the delta of contentOffset. The problem with this is that the uitableview bounces back so it always gets into the first branch of the if. But even if I solve this problem I feel like I'll just patch it. I'm sure there's a way more elegant way of achieving the effect in the video having the same responsiveness.
Any suggestion will be much appreciated.
Thanks
I'm not sure if this is what you want but I hacked up a quick demo:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate>
#property (nonatomic, strong) UIView *headerView;
#property (nonatomic, strong) UILabel *lblTitle;
#property (nonatomic, strong) UIButton *btnReset;
#property (nonatomic, strong) UIImageView *imageView;
#property (nonatomic, strong) UIScrollView *scrollView;
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, strong) NSLayoutConstraint *scrollViewTopConstraint;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//self.view.backgroundColor = [UIColor whiteColor];
[self initViews];
[self initConstraints];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)initViews
{
self.view.backgroundColor = [UIColor colorWithRed:43.0/255.0 green:39.0/255.0 blue:55.0/255.0 alpha:1.0];
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.backgroundColor = [UIColor clearColor];
self.scrollView.alwaysBounceVertical = YES;
self.scrollView.delegate = self;
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = [UIColor colorWithRed:43.0/255.0 green:39.0/255.0 blue:55.0/255.0 alpha:1.0];
self.headerView.layer.shadowColor = [UIColor blackColor].CGColor;
self.headerView.layer.shadowOffset = CGSizeMake(0,0);
self.headerView.layer.shadowOpacity = 0.25;
self.headerView.layer.shadowRadius = 4;
self.lblTitle = [[UILabel alloc] init];
self.lblTitle.text = #"HEADER VIEW";
self.lblTitle.textColor = [UIColor whiteColor];
self.lblTitle.textAlignment = NSTextAlignmentCenter;
self.btnReset = [[UIButton alloc] init];
[self.btnReset setTitle:#"Reset" forState:UIControlStateNormal];
self.btnReset.backgroundColor = [UIColor colorWithRed:0.75 green:0.0 blue:0.0 alpha:1.0];
self.btnReset.layer.cornerRadius = 5.0;
[self.btnReset addTarget:self action:#selector(resetView) forControlEvents:UIControlEventTouchUpInside];
self.imageView = [[UIImageView alloc] init];
self.imageView.backgroundColor = [UIColor colorWithRed:43.0/255.0 green:39.0/255.0 blue:55.0/255.0 alpha:1.0];
self.tableView = [[UITableView alloc] init];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.rowHeight = 150.0;
self.tableView.layer.shadowColor = [UIColor blackColor].CGColor;
self.tableView.layer.shadowOffset = CGSizeMake(0,-5);
self.tableView.layer.shadowOpacity = 0.5;
self.tableView.layer.shadowRadius = 20;
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.scrollEnabled = NO;
self.tableView.clipsToBounds = NO;
[self.headerView addSubview:self.lblTitle];
[self.headerView addSubview:self.btnReset];
[self.scrollView addSubview:self.tableView];
[self.view addSubview:self.imageView];
[self.view addSubview:self.scrollView];
[self.view addSubview:self.headerView];
}
-(void)initConstraints
{
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
self.lblTitle.translatesAutoresizingMaskIntoConstraints = NO;
self.btnReset.translatesAutoresizingMaskIntoConstraints = NO;
self.imageView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"scrollView": self.scrollView,
#"headerView": self.headerView,
#"lblTitle": self.lblTitle,
#"btnReset": self.btnReset,
#"imageView": self.imageView,
#"tableView": self.tableView
};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[scrollView]" options:0 metrics:nil views:views]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0]];
self.scrollViewTopConstraint = [NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0];
[self.view addConstraint:self.scrollViewTopConstraint];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[headerView(320)]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[headerView(50)]" options:0 metrics:nil views:views]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[tableView(320)]|" options:0 metrics:nil views:views]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-150-[tableView(300)]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[imageView(320)]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[imageView(320)]" options:0 metrics:nil views:views]];
[self.headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[lblTitle]|" options:0 metrics:nil views:views]];
[self.headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[lblTitle]|" options:0 metrics:nil views:views]];
[self.headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[btnReset(80)]-5-|" options:0 metrics:nil views:views]];
[self.headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-8-[btnReset]-8-|" options:0 metrics:nil views:views]];
}
-(BOOL)prefersStatusBarHidden
{
return YES;
}
#pragma mark - TableView Methods -
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 2;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.backgroundColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0];
return cell;
}
#pragma mark - ScrollView Delegate -
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//NSLog(#"scrollView offset = %lf", scrollView.contentOffset.y);
if(scrollView.contentOffset.y <= -145)
{
//self.scrollView.scrollEnabled = NO;
self.scrollViewTopConstraint.constant = self.view.bounds.size.height;
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.scrollView layoutIfNeeded];
} completion:^(BOOL finished) {
}];
}
}
-(void)resetView
{
self.scrollViewTopConstraint.constant = 0;
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[self.scrollView layoutIfNeeded];
} completion:^(BOOL finished) {
}];
}
What you get when you open the app:
Then you drag down to the edge, the view snaps open:
Press the red reset button to bring it back up :D

Using autolayout in UIScrollView subviews (programmatically)

First of all I've been reading all questions similar to this one, but with no success, so finally I'll try asking my specific case.
I have a UIScrollView that I fill with components programmatically this way:
- (void) fillScrollView(int numItems)
{
float posY = 10.0;
for(int i = 0; i < numItems; i++)
{
UIImageView *leftImg = [[UIImageView alloc] init];
[leftImg setTranslatesAutoresizingMaskIntoConstraints:NO];
[leftImg setFrame:CGRectMake(10.0, posY, 20.0, 20.0)];
[leftImg setImage:[UIImage imageNamed:#"img1"]];
UILabel *txtLb = [[UILabel alloc] init];
[txtLb setTranslatesAutoresizingMaskIntoConstraints:NO];
[txtLb setFont:[UIFont systemFontOfSize:15.0]];
[txtLb setNumberOfLines:0];
[txtLb setLineBreakMode:NSLineBreakByWordWrapping];
[txtLb setFrame:CGRectMake(40.0, posY, 240.0, 20.0)];
NSString *data = #"This is my example text, it could be longer.";
[txtLb setText:data];
CGRect paragraphRect = [dato boundingRectWithSize:CGSizeMake(txtLb.frame.size.width, 9999.0)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName: txtLb.font}
context:nil];
float height = paragraphRect.size.height;
CGRect frame = txtLb.frame;
frame.size.height = ceil(height);
[txtLb setFrame:frame];
UIImageView *rightImg = [[UIImageView alloc] init];
[rightImg setTranslatesAutoresizingMaskIntoConstraints:NO];
[rightImg setFrame:CGRectMake(290.0, posY, 20.0, 20.0)];
[rightImg setImage:[UIImage imageNamed:#"img2"]];
[_scrollV addSubview:leftImg];
[_scrollV addSubview:txtLb];
[_scrollV addSubview:rightImg];
height = height + 20.0;
if(height < 40.0) height = 40.0;
posY = posY + height;
}
[_scrollV setContentSize:CGSizeMake(_scrollV.frame.size.width, posY)];
}
I would like that theis constraints were:
H:|-10-[leftImg(20)]-10-[txtLb]-10-[rightImg(20)]-10-|
And vertically each row has a space of 10px of vertical separation from the row above.
I've tried using constraintWithItem but I'm confused about how to use it in this case.
Any help would be very appreciated. Kind regards!
EDIT
Following Zhang's suggestion I've put the 3 components inside a UIView. This way I can use autolayout between them without problems and everything is in the correct position inside each UIView.
However I'm still having problems using autolayout between UIViews inside the loop. I'm doing this:
All blocks have no left/right margin with the UIScrollView.
// 0px to the left of the UIScrollView
NSLayoutConstraint *constraintLeft = [NSLayoutConstraint constraintWithItem:block
attribute:NSLayoutAttributeLeftMargin
relatedBy:NSLayoutRelationEqual
toItem:_scrollV
attribute:NSLayoutAttributeRightMargin
multiplier:1.0
constant:0.0];
// 0px to the right of the UIScrollView
NSLayoutConstraint *constraintRight = [NSLayoutConstraint constraintWithItem:block
attribute:NSLayoutAttributeRightMargin
relatedBy:NSLayoutRelationEqual
toItem:_scrollV
attribute:NSLayoutAttributeLeftMargin
multiplier:1.0
constant:0.0];
[_scrollV addConstraint:constraintLeft];
[_scrollV addConstraint:constraintRight];
Regarding to the vertical separation between blocks, when the UIView is the first block of the UIScrollView:
// 10px below UIScrollView top
NSLayoutConstraint *constraintTop = [NSLayoutConstraint constraintWithItem:block
attribute:NSLayoutAttributeTopMargin
relatedBy:NSLayoutRelationEqual
toItem:_scrollV
attribute:NSLayoutAttributeBottomMargin
multiplier:1.0
constant:10.0];
[_scrollV addConstraint:constraintTop];
And when the UIView has any block above it:
// 10px below previous block
NSLayoutConstraint *constraintTop = [NSLayoutConstraint constraintWithItem:block
attribute:NSLayoutAttributeTopMargin
relatedBy:NSLayoutRelationEqual
toItem:previousBlock
attribute:NSLayoutAttributeBottomMargin
multiplier:1.0
constant:10.0];
[_scrollV addConstraint:constraintTop];
This shows all blocks without vertical separation, all in the same Y position, and also give errors applying constraints.
I'm sure I'm not using the right way constraintWithItem, but I can not find examples for this use.
It seems like you're trying to reinvent the wheel mate. You probably should be using UICollectionView or UITableView instead of UIScrollView and manually adding your cells.
Anyhow, for your scrollView method, one way you can implement it is like this:
ViewController Header File
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (nonatomic, strong) UIScrollView *scrollView;
#property (nonatomic, strong) UIView *contentView;
#end
ViewController Implementation File
#import "ViewController.h"
#import "Cell.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initViews];
[self initConstraints];
[self fillScrollView:15];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)prefersStatusBarHidden
{
return YES;
}
-(void)initViews
{
self.scrollView = [[UIScrollView alloc] init];
// ------------------------------------------------------------------
// This content view will be the only child view of scrollview
// ------------------------------------------------------------------
self.contentView = [[UIView alloc] init];
// add content view to scrollview now
[self.scrollView addSubview:self.contentView];
// add scrollview to main view
[self.view addSubview:self.scrollView];
}
-(void)initConstraints
{
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"scrollView": self.scrollView,
#"contentView": self.contentView
};
// setup scrollview constraints
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]|" options:0 metrics:nil views:views]];
// ---------------------------------------
// setup content view constraint
//
// note: need to pin all four side of
// contentView to scrollView
// ---------------------------------------
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[contentView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[contentView]|" options:0 metrics:nil views:views]];
}
-(void)fillScrollView:(int) numItems
{
// clear any previous cells before adding new ones
[self.contentView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
// Need to construct the layout visual format string
NSMutableString *strVerticalConstraint = [[NSMutableString alloc] init];
[strVerticalConstraint appendString:#"V:|"];
// this dictionary will hold all the key-value pair that identifies all the subviews
NSMutableDictionary *subviews = [[NSMutableDictionary alloc] init];
for(int i = 0; i < numItems; i++)
{
Cell *cell = [[Cell alloc] init];
// customize the cell's appearance here
cell.leftImage.image = [UIImage imageNamed:#"leftImage.png"];
cell.textLabel.text = #"This is my example text, it could be longer.";
cell.rightImage.image = [UIImage imageNamed:#"rightImage.png"];
[self.contentView addSubview:cell];
cell.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"cell": cell
};
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[cell]|" options:0 metrics:nil views:views]];
// prevent cell's width to extend beyond screen width
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1.0 constant:self.view.bounds.size.width]];
// cell name
NSString *cellName = [[NSString alloc] initWithFormat:#"cell%d", i];
// construct each cell's vertical constraint to add it strVerticalConstraint
NSString *viewName = nil;
if(i < numItems - 1)
{
viewName = [[NSString alloc] initWithFormat:#"[%#(50)]-10-", cellName];
}
else
{
viewName = [[NSString alloc] initWithFormat:#"[%#(50)]", cellName];
}
[strVerticalConstraint appendString:viewName];
// add cell name to dictionary
[subviews setValue:cell forKey:cellName];
}
[strVerticalConstraint appendString:#"|"];
NSLog(#"strVerticalConstraint: \n%#", strVerticalConstraint);
// Finally, use the long vertical constraint string
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:strVerticalConstraint options:0 metrics:nil views:subviews]];
}
#end
Cell Header File
#import <UIKit/UIKit.h>
#interface Cell : UIView
#property (nonatomic, strong) UIImageView *leftImage;
#property (nonatomic, strong) UILabel *textLabel;
#property (nonatomic, strong) UIImageView *rightImage;
#end
Cell Implementation File
#import "Cell.h"
#implementation Cell
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self initViews];
[self initConstraints];
}
return self;
}
-(void)initViews
{
self.backgroundColor = [UIColor grayColor];
self.leftImage = [[UIImageView alloc] init];
self.leftImage.contentMode = UIViewContentModeScaleAspectFill;
self.leftImage.clipsToBounds = YES;
self.leftImage.layer.cornerRadius = 10.0;
self.textLabel = [[UILabel alloc] init];
self.textLabel.numberOfLines = 0;
self.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.rightImage = [[UIImageView alloc] init];
self.rightImage.contentMode = UIViewContentModeScaleAspectFill;
self.rightImage.layer.cornerRadius = 10.0;
self.rightImage.clipsToBounds = YES;
[self addSubview:self.leftImage];
[self addSubview:self.textLabel];
[self addSubview:self.rightImage];
}
-(void)initConstraints
{
self.leftImage.translatesAutoresizingMaskIntoConstraints = NO;
self.textLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.rightImage.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"leftImage": self.leftImage,
#"textLabel": self.textLabel,
#"rightImage": self.rightImage
};
// horizontal constraints
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[leftImage(20)]-10-[textLabel]-[rightImage(20)]-10-|" options:0 metrics:nil views:views]];
// vertical constraints
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.leftImage attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.rightImage attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[leftImage(20)]" options:0 metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[rightImage(20)]" options:0 metrics:nil views:views]];
}
#end
You should see something like this:
Maybe you have your reason's for using a scrollView and manually adding each row, otherwise, if you're open to alternative, you can use UICollectionView or UITableView.
The method above will result in a lot of memory use as you can imagine if you had 1000 rows, the app needs to calculate, rendering and store 1000 rows in memory. Not scalable, and not feasible.
That's where UITableView or UICollectionView comes in, they reuse each cell when it goes offscreen that way, you'll only ever need to render and store the visible cells on screen.
UICollectionView Demo
So, if you want to see a UICollectionView approach, this is a demo of how you can do it:
ViewController Header File
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
#property (nonatomic, strong) UICollectionView *collectionView;
#property (nonatomic, strong) NSArray *items;
#end
ViewController Implementation File
#import "ViewController.h"
#import "CustomCell.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initViews];
[self initConstraints];
// --------------------------------------------------------
// Hardcoding 15 sample items as the data source.
// Your data might be from a JSON webservice REST API.
// --------------------------------------------------------
self.items = #[
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer.",
#"This is my example text, it could be longer."
];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)initViews
{
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.minimumInteritemSpacing = 0;
flowLayout.minimumLineSpacing = 10;
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
self.collectionView.backgroundColor = [UIColor whiteColor];
// need to tell CollectionView beforehand the cell class you want to use
[self.collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:#"cellID"];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.view addSubview:self.collectionView];
}
-(void)initConstraints
{
self.collectionView.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"collectionView": self.collectionView
};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[collectionView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[collectionView]|" options:0 metrics:nil views:views]];
}
#pragma mark - UICollectionView Methods -
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.items.count;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// note: reuse identifier must match what you specified in the register cell above
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cellID" forIndexPath:indexPath];
// ---------------------------------------------------------------
// hardcoding images here, you might load your images from JSON
// data using an image caching library like SDWebImage
// ---------------------------------------------------------------
cell.leftImage.image = [UIImage imageNamed:#"leftImage.png"];
// getting text data from data source "self.items"
cell.textLabel.text = self.items[indexPath.row];
cell.rightImage.image = [UIImage imageNamed:#"rightImage.png"];
return cell;
}
// ----------------------------------------------------------------
// Tells the collection view the width and height of each cell
// ----------------------------------------------------------------
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGSize size = CGSizeMake(self.view.frame.size.width, 50.0);
return size;
}
#end
CustomCell Header File
#import <UIKit/UIKit.h>
#interface CustomCell : UICollectionViewCell
#property (nonatomic, strong) UIImageView *leftImage;
#property (nonatomic, strong) UILabel *textLabel;
#property (nonatomic, strong) UIImageView *rightImage;
#end
CustomCell Implementation File
#import "CustomCell.h"
#implementation CustomCell
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self initViews];
[self initConstraints];
}
return self;
}
-(void)initViews
{
self.backgroundColor = [UIColor grayColor];
self.leftImage = [[UIImageView alloc] init];
self.leftImage.contentMode = UIViewContentModeScaleAspectFill;
self.leftImage.clipsToBounds = YES;
self.leftImage.layer.cornerRadius = 10.0;
self.textLabel = [[UILabel alloc] init];
self.textLabel.numberOfLines = 0;
self.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.rightImage = [[UIImageView alloc] init];
self.rightImage.contentMode = UIViewContentModeScaleAspectFill;
self.rightImage.layer.cornerRadius = 10.0;
self.rightImage.clipsToBounds = YES;
[self.contentView addSubview:self.leftImage];
[self.contentView addSubview:self.textLabel];
[self.contentView addSubview:self.rightImage];
}
-(void)initConstraints
{
self.leftImage.translatesAutoresizingMaskIntoConstraints = NO;
self.textLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.rightImage.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"leftImage": self.leftImage,
#"textLabel": self.textLabel,
#"rightImage": self.rightImage
};
// horizontal constraints
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[leftImage(20)]-10-[textLabel]-[rightImage(20)]-10-|" options:0 metrics:nil views:views]];
// vertical constraints
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.leftImage attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.rightImage attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[leftImage(20)]" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[rightImage(20)]" options:0 metrics:nil views:views]];
}
#end
You end up with something like this:
Look the same but more efficient :D
No I didn't upload the same screenshot :P
Hope that helps?

Resources