UILabel height animation with autolayout - ios

I have an UILabel on my view and UIButton. When button touched UILabel should change height animated, depends on label content . I was trying this:
- (void)viewDidLoad {
self.textLabel= [[UILabel alloc] initWithFrame:CGRectZero];
self.textLabel.numberOfLines=0;
self.textLabel.font= [UIFont systemFontOfSize:14];
self.textLabel.backgroundColor= [UIColor lightGrayColor];
self.textLabel.text= #"short text";
[self.view addSubview:self.textLabel];
[self.textLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[_textLabel]-10-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(_textLabel)]];
self.button= [UIButton buttonWithType:UIButtonTypeSystem];
[self.button addTarget:self action:#selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];
[self.button setTitle:#"Tap" forState:UIControlStateNormal];
self.button.backgroundColor= [UIColor greenColor];
[self.button setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:self.button];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[_button]-10-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(_button)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-50-[_textLabel(>=0)]-10-[_button(==20)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(_textLabel,_button)]];
}
- (void)buttonTouched:(id)buttonTouched {
self.shortText =!self.shortText;
self.textLabel.text= self.shortText ?#"short text":#"long long long text\nlong long long text\nlong long long text\n";
[UIView animateWithDuration:1.0
animations:^{
[self.view layoutIfNeeded];
}];
}

Right before the animation block, you need to call [self.view setNeedsUpdateConstraints] in order to trigger tell the view that the constraints need to be updated when you call layoutIfNeeded
So the new method:
- (void)buttonTouched:(id)buttonTouched {
self.shortText =!self.shortText;
self.textLabel.text= self.shortText ?#"short text":#"long long long text\nlong long long text\nlong long long text\n";
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:1.0
animations:^{
[self.view layoutIfNeeded];
}];
}

I have this example working no problem.
#interface ViewController ()
#end
#implementation ViewController
{
__weak UIView *_bgView;
__weak UILabel *_label;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView *bgView = [[UIView alloc] initWithFrame:CGRectZero];
bgView.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.5];
bgView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:bgView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[bgView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(bgView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[bgView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(bgView)]];
_bgView = bgView;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.5];
label.text = #"ahoj";
label.numberOfLines = 99;
label.textAlignment = NSTextAlignmentCenter;
label.translatesAutoresizingMaskIntoConstraints = NO;
[bgView addSubview:label];
[bgView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-8-[label]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label)]];
[bgView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-8-[label]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label)]];
_label = label;
[self performSelector:#selector(animate) withObject:nil afterDelay:1];
}
- (void)animate
{
_label.text = #"ahoj, ahoj\ntotalka ahoj";
[UIView animateWithDuration:1 animations:^{
[_bgView.superview layoutIfNeeded];
} completion:^(BOOL finished) {
;
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

Define the height constraint in your storyboard, add it as an IBOutlet, and then change its value inside your animation block.

Maybe if you use
[self.textLabel sizeToFit];
it works.

Related

How to Push one UIview to another UIview in ios using Animation concept?

Hi I am very new in iOS and in my project I have added two UIViews programmatically on my main UIViewController.
Here my main requirement is when I click "Next" button which is in my firstView, I want to push the FirstView to SecondView and
when I click "Back" button which is in the SecondView, I want to pushBack secondView to firstView.
As in how to push one UIViewController to another UIViewController?
But same requirement I want to do Using UIView programmatically.
Please help me.
How can we do this?
my code:-
#import "ViewController.h"
#interface ViewController ()
{
UIView * FisrtView;
UIView * SecondView;
UIButton * Next;
UIButton * Back;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
FisrtView = [[UIView alloc] init];
FisrtView.backgroundColor=[UIColor lightGrayColor];
FisrtView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:FisrtView];
SecondView = [[UIView alloc] init];
SecondView.backgroundColor=[UIColor orangeColor];
SecondView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:SecondView];
Next = [[UIButton alloc] init];
Next.backgroundColor=[UIColor orangeColor];
Next.translatesAutoresizingMaskIntoConstraints = NO;
[Next setTitle:#"Go Next" forState:UIControlStateNormal];
[Next addTarget:self action:#selector(Next:) forControlEvents:UIControlEventTouchUpInside];
[FisrtView addSubview:Next];
Back = [[UIButton alloc] init];
Back.backgroundColor=[UIColor lightGrayColor];
Back.translatesAutoresizingMaskIntoConstraints = NO;
[Back setTitle:#"Go Back" forState:UIControlStateNormal];
[Back addTarget:self action:#selector(Back:) forControlEvents:UIControlEventTouchUpInside];
[SecondView addSubview:Back];
//Applting Autolayouts for All Fields
NSDictionary * HeaderDictionary = NSDictionaryOfVariableBindings(FisrtView,SecondView,Next,Back);
//Appliying Autolayouts for FirstView
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-0-[FisrtView]-0-|"]
options:0
metrics:nil
views:HeaderDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-0-[FisrtView]-0-|"]
options:0
metrics:nil
views:HeaderDictionary]];
//Appying Autolayoust for NextButton
[FisrtView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-10-[Next]-10-|"]
options:0
metrics:nil
views:HeaderDictionary]];
[FisrtView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-100-[Next(30)]"]
options:0
metrics:nil
views:HeaderDictionary]];
//Appliying Autolayouts for secondView
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-0-[SecondView]-0-|"]
options:0
metrics:nil
views:HeaderDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-0-[SecondView]-0-|"]
options:0
metrics:nil
views:HeaderDictionary]];
//Appying Autolayoust for BackButton
[SecondView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-10-[Back]-10-|"]
options:0
metrics:nil
views:HeaderDictionary]];
[SecondView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-100-[Back(30)]"]
options:0
metrics:nil
views:HeaderDictionary]];
SecondView.hidden = YES;
FisrtView.hidden = NO;
}
-(void)Next:(id)sender{
SecondView.frame=CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); //your view start position
[UIView animateWithDuration:0.15f
delay:0.0f
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
[SecondView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; // final visible position
}
completion:nil];
SecondView.hidden = NO;
}
-(void)Back:(id)sender{
SecondView.hidden = YES;
FisrtView.hidden = NO;
}
#end
initial mistake, you were create the button is wrong and does not set the frame to visible area
not like
Next = [[UIButton alloc] init];
do like
Next = [UIButton buttonWithType: UIButtonTypeRoundedRect];
Next.frame = CGRectMake(210, 285, 100, 18)];
Next.translatesAutoresizingMaskIntoConstraints = NO;
[Next setTitle:#"Go Next" forState:UIControlStateNormal];
[Next addTarget:self action:#selector(Next:) forControlEvents:UIControlEventTouchUpInside];
[FisrtView addSubview:Next];
and forget to add frame for visible area in view
FisrtView = [[UIView alloc] init];
FisrtView.frame = CGRectMake(210, 285, 100, 18)];
SecondView = [[UIView alloc] init];
SecondView.frame = CGRectMake(210, 285, 100, 18)];
for sample animation
-(void)Next:(id)sender{
SecondView.frame=CGRectMake(248, -420, 500, 414); //your view start position
[UIView animateWithDuration:0.5f
delay:0.0f
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
[SecondView setFrame:CGRectMake(248, 30, 500, 414)]; // final visible position
}
completion:nil];
}
for sample animation see this link
Please refer following link.
hope this will help you.
http://googleweblight.com/?lite_url=https://stackoverflow.com/questions/2215672/how-to-change-the-push-and-pop-animations-in-a-navigation-based-app&ei=Qc-ODruI&lc=en-IN&s=1&m=775&ts=1447514312&sig=APONPFlwklDRNHSybRHp3xVcrDKmQUeRjg

Cannot select/edit text in UITextView within UIScrollView

I have setup my UIScrollView with subviews like so using Masonry:
- (void)setupViews {
self.view.backgroundColor = [UIColor Background];
self.scrollView = [UIScrollView new];
self.scrollView.alwaysBounceVertical = YES;
[self.view addSubview:self.scrollView];
[self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
self.contentView = [UIView new];
[self.scrollView addSubview:self.contentView];
self.scrollView.backgroundColor = [UIColor clearColor];
[self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.scrollView);
make.left.and.right.equalTo(self.view);
}];
self.imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.imageButton sd_setImageWithURL:[NSURL URLWithString:self.card.cardImageURL] forState:UIControlStateNormal];
[self.imageButton.imageView setContentMode:UIViewContentModeScaleAspectFill];
[self.contentView addSubview:self.imageButton];
[self.imageButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.and.right.equalTo(self.contentView);
make.height.equalTo(self.imageButton.mas_width).multipliedBy(3/4.0);
}];
self.textField = [UITextField new];
self.textField.backgroundColor = [UIColor whiteColor];
self.textField.font = kFontRegular(14);
self.textField.text = self.card.cardTitle;
[self.contentView addSubview:self.textField];
[self.textField mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).with.offset(8);
make.top.equalTo(self.imageButton.mas_bottom).with.offset(8);
make.right.equalTo(self.contentView).with.offset(-8);
make.height.equalTo(#(45));
}];
}
but it will not let me interact with the UITextField. what element here is preventing user interaction?
Your contentView's height will be zero. So it will never get some touch events. You should not use this constraint:
make.edges.equalTo(self.scrollView);
It will not get a correct value. Try to set top and height constraints for your contentView.
make.top.equalTo(#0);
make.height.equalTo(#700);

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

adding NSLayoutConstraint makes views disappear

I have a simple view (controller) with two subviews:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *viewA = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewA.backgroundColor = [UIColor redColor];
[self.view addSubview:viewA];
UIView *viewB = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
viewB.translatesAutoresizingMaskIntoConstraints = NO;
viewB.backgroundColor = [UIColor grayColor];
[self.view addSubview:viewB];
}
Of course they are overlapping at this point (i can only see viewB). So I add a constraint to make viewB go below viewA, like this:
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewB
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:viewA
attribute:NSLayoutAttributeBottom
multiplier:1.f
constant:0]];
This makes both views disappear. What am I doing wrong?
Thanks!
When using constraints, you should do everything with constraints (no setting of frames), so adding one constraint isn't enough to define you positions and sizes. I'm not sure why adding the one constraint negated the sizes you set for the views, but it seems that it does. You should do something like this to fully describe the views,
- (void)viewDidLoad {
[super viewDidLoad];
UIView *viewA = [UIView new];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewA.backgroundColor = [UIColor redColor];
[self.view addSubview:viewA];
UIView *viewB = [UIView new];
viewB.translatesAutoresizingMaskIntoConstraints = NO;
viewB.backgroundColor = [UIColor grayColor];
[self.view addSubview:viewB];
NSDictionary *dict = NSDictionaryOfVariableBindings(viewA,viewB);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[viewA(==50)]" options:0 metrics:nil views:dict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"[viewB(==50)]" options:0 metrics:nil views:dict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[viewA(==50)][viewB(==50)]" options:NSLayoutFormatAlignAllLeft metrics:nil views:dict]];
}

Creating a UICollectionViewCell with UIImage and UILabels creates slow scrolling

I create a subview with a UIview (acts as header), a UIImage, and 10 UILabels. I'm putting these into a UICollectionView as cells.
When designed completely, it does not scroll smoothly. If i remove all the UILabels, it scrolls smoothly.
I'm assuming it's sluggish cause the UICollectionView loads on demand, so when it needs each new cell, it has to draw it which locks up the main thread.
Is it just a matter that its too much for iOS to handle to create them? If so, is there another way I can put text into it?
what my cell looks like:
Here is DatasetFilterListPanelView, this creates the UIView that I put into the UICollectionViewCell. I did it this way cause I created this before I decided to use UICollectionView.
#implementation DatasetFilterListPanelView
-(id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.translatesAutoresizingMaskIntoConstraints = FALSE;
UIView *contentView = [self createContentView];
[self addSubview:contentView];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[contentView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[contentView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
}
return self;
}
-(UIView *) createContentView {
UIView *contentView = [[UIView alloc] initWithFrame:self.frame];
// contentView.translatesAutoresizingMaskIntoConstraints = FALSE;
contentView.backgroundColor = [UIColor myDarkGrayColor];
UIView *headerView = [self createHeaderView];
[contentView addSubview:headerView];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[headerView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(headerView)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[headerView]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(headerView)]];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"gear12.png"]];
imageView.translatesAutoresizingMaskIntoConstraints = FALSE;
imageView.backgroundColor = [UIColor blueColor];
self.imageView = imageView;
[imageView addConstraint:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:imageView attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[contentView addSubview:imageView];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[imageView]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(imageView)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-[imageView]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(headerView, imageView)]];
UILabel *acresLabel = [self createLabelWithTitle:#"Label01:" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE_BOLD size:12]];
[contentView addSubview:acresLabel];
UILabel *addedLabel = [self createLabelWithTitle:#"Label02:" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE_BOLD size:12]];
[contentView addSubview:addedLabel];
UILabel *typeLabel = [self createLabelWithTitle:#"Label03:" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE_BOLD size:12]];
[contentView addSubview:typeLabel];
UILabel *zonesLabel = [self createLabelWithTitle:#"Label04:" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE_BOLD size:12]];
[contentView addSubview:zonesLabel];
UILabel *sceneLabel = [self createLabelWithTitle:#"Label05:" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE_BOLD size:12]];
[contentView addSubview:sceneLabel];
UILabel *acresValueLabel = [self createLabelWithTitle:#"Data" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE size:12]];
acresValueLabel.textAlignment = NSTextAlignmentLeft;
[contentView addSubview:acresValueLabel];
UILabel *addedValueLabel = [self createLabelWithTitle:#"Data" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE size:12]];
addedValueLabel.textAlignment = NSTextAlignmentLeft;
[contentView addSubview:addedValueLabel];
UILabel *typeValueLabel = [self createLabelWithTitle:#"Name" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE size:12]];
typeValueLabel.textAlignment = NSTextAlignmentLeft;
[contentView addSubview:typeValueLabel];
UILabel *zonesValueLabel = [self createLabelWithTitle:#"Data" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE size:12]];
zonesValueLabel.textAlignment = NSTextAlignmentLeft;
[contentView addSubview:zonesValueLabel];
UILabel *sceneValueLabel = [self createLabelWithTitle:#"Name" andFont:[UIFont fontWithName:HELVETICA_FONT_STYLE size:12]];
sceneValueLabel.textAlignment = NSTextAlignmentLeft;
[contentView addSubview:sceneValueLabel];
NSDictionary *views = NSDictionaryOfVariableBindings(headerView, imageView, acresLabel, acresValueLabel, addedLabel, addedValueLabel, typeLabel, typeValueLabel, zonesLabel, zonesValueLabel, sceneLabel, sceneValueLabel);
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-[acresLabel]"
options:0
metrics:nil
views:views]] ;
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[acresLabel]-[addedLabel(==acresLabel)]-[typeLabel(==acresLabel)]-[zonesLabel(==acresLabel)]-[sceneLabel(==acresLabel)]-|"
options:NSLayoutFormatAlignAllRight
metrics:0
views:views]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[acresValueLabel]-[addedValueLabel(==acresLabel)]-[typeValueLabel(==acresLabel)]-[zonesValueLabel(==acresLabel)]-[sceneValueLabel(==acresLabel)]-|"
options:NSLayoutFormatAlignAllLeft
metrics:nil
views:views]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-20-[acresLabel]-[acresValueLabel]" options:0 metrics:nil views:views]];
return contentView;
}
-(UIView *)createHeaderView {
UIView *view = [UIView new];
view.translatesAutoresizingMaskIntoConstraints = FALSE;
view.backgroundColor = [UIColor blueColor];
view.clipsToBounds = YES;
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[view(30)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)]];
UILabel *title = [UILabel new];
title.translatesAutoresizingMaskIntoConstraints = FALSE;
title.text = #"Default text";
title.font = [UIFont fontWithName:HELVETICA_FONT_STYLE_BOLD size:14];
title.textColor = [UIColor whiteColor];
title.backgroundColor = [UIColor clearColor];
self.headerLabel = title;
[view addSubview:title];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[title]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(title)]];
[view addConstraint:[NSLayoutConstraint constraintWithItem:title attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
self.headerGradient = [UIColor grayGradient];
self.headerGradient.frame = CGRectMake(0, 0, 360, 30);
[view.layer insertSublayer:self.headerGradient atIndex:0];
return view;
}
-(UILabel *)createLabelWithTitle:(NSString *)title andFont:(UIFont *)font; {
UILabel *label = [UILabel new];
label.translatesAutoresizingMaskIntoConstraints = FALSE;
label.text = title;
label.font = font;
label.textAlignment = NSTextAlignmentRight;
label.textColor = [UIColor whiteColor];
label.backgroundColor = [UIColor clearColor];
return label;
}
Here is my UICollectionViewCell file, i just addSubview a DatasetFilterListPanelView to it.
#implementation DatasetViewCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self addSubview:[[DatasetFilterListPanelView alloc] initWithFrame:CGRectMake(0, 0, 360, 160)]];
}
return self;
}
When I use the same panels in a UIScrollview, once they are all loaded and positioned, it will scroll smoothly. So it has to be the loading a cell on demand aspect of the UICollectionView.
I followed this UICollectionView Tutorial
EDIT: creating the cell:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
DatasetViewCell *datasetCell = [collectionView dequeueReusableCellWithReuseIdentifier:DatasetCellIdentifier forIndexPath:indexPath];
return datasetCell;
}
EDIT 2: Instrument tracing:
Ok, after much playing around I figured out the culprit: constraints! CodaFI was right. I didn't have that many constraints in the panel so i didn't think it could be the issue.
I created a nib file and removed autolayout and it now scrolls smoothly.
Lesson of the day: Constraints are slow to compute!
Generally the problem is that you don't reuse the cells. Make sure you use dequeueReusableCellWithReuseIdentifier:forIndexPath: to reuse existing cells.

Resources