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
Related
I am trying to use UIScrollView with paging enabled. I am adding various UIView to UISCrollView as a subviews. I want those subview to be smaller than size of scroll view so I have modified my constrains accordingly. Now when I actually swipe them left/ right then do not happened to be in center. I was expecting it to show previous / next view peeking from sides with current page in center.
This is what it looks like
Below is my code scrollview implementation
//
// ViewController.m
// Paging
//
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) UIScrollView *pagingScrollView;
#end
#implementation ViewController
- (UIScrollView *)pagingScrollView {
if (!_pagingScrollView) {
_pagingScrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
_pagingScrollView.translatesAutoresizingMaskIntoConstraints = NO;
_pagingScrollView.backgroundColor = [UIColor orangeColor];
_pagingScrollView.showsHorizontalScrollIndicator = NO;
_pagingScrollView.showsVerticalScrollIndicator = NO;
_pagingScrollView.contentInset = UIEdgeInsetsZero;
_pagingScrollView.pagingEnabled = YES;
_pagingScrollView.clipsToBounds = NO;
_pagingScrollView.bounces = NO;
}
return _pagingScrollView;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self scrollViewSetUp];
NSDictionary *views = NSDictionaryOfVariableBindings(_pagingScrollView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_pagingScrollView]|"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_pagingScrollView]|"
options:0
metrics:nil
views:views]];
}
- (void)scrollViewSetUp {
[self.view addSubview:self.pagingScrollView];
UIView *lastView = nil;
NSInteger arrayCount = 5;
for(NSInteger index = 0; index < arrayCount; index++)
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.translatesAutoresizingMaskIntoConstraints = NO;
view.backgroundColor = [UIColor yellowColor];
[self.pagingScrollView addSubview:view];
[self.pagingScrollView addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.pagingScrollView
attribute:NSLayoutAttributeTop
multiplier:1
constant:40]];
[self.pagingScrollView addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.pagingScrollView
attribute:NSLayoutAttributeHeight
multiplier:0.80
constant:0]];
[self.pagingScrollView addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.pagingScrollView
attribute:NSLayoutAttributeWidth
multiplier:0.80
constant:0]];
if (lastView == nil && index == 0){
[self.pagingScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-20-[view(==_pagingScrollView)]"
options:0
metrics:nil
views:#{#"view":view, #"_pagingScrollView":_pagingScrollView}]];
} else {
[self.pagingScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[lastView]-20-[view]"
options:0
metrics:nil
views:#{#"lastView":lastView, #"view":view, #"_pagingScrollView":_pagingScrollView}]];
}
if(index == arrayCount-1) {
[self.pagingScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[view]-20-|"
options:0
metrics:nil
views:#{#"view":view}]];
}
lastView = view;
}
}
#end
Any pointers/comments/feedback highly appreciated. Thanks.
Is this you want?
//
// ViewController.h
// Test
//
// Created by Lee on 7/8/16.
// Copyright © 2016 Lee. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (nonatomic, strong) UIScrollView *pagingScrollView;
#end
//
// ViewController.m
// Test
//
// Created by Lee on 7/8/16.
// Copyright © 2016 Lee. All rights reserved.
//
#import "ViewController.h"
#interface ViewController ()<UIScrollViewDelegate>
#property (nonatomic,strong)NSMutableArray *subviewsCenterArray;
#end
#implementation ViewController
- (UIScrollView *)pagingScrollView {
if (!_pagingScrollView) {
_pagingScrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
_pagingScrollView.translatesAutoresizingMaskIntoConstraints = NO;
_pagingScrollView.backgroundColor = [UIColor orangeColor];
_pagingScrollView.showsHorizontalScrollIndicator = NO;
_pagingScrollView.showsVerticalScrollIndicator = NO;
_pagingScrollView.contentInset = UIEdgeInsetsZero;
_pagingScrollView.pagingEnabled = NO;
_pagingScrollView.clipsToBounds = NO;
_pagingScrollView.bounces = NO;
_pagingScrollView.delegate = self;
}
return _pagingScrollView;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self scrollViewSetUp];
NSDictionary *views = NSDictionaryOfVariableBindings(_pagingScrollView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_pagingScrollView]|"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_pagingScrollView]|"
options:0
metrics:nil
views:views]];
}
- (void)scrollViewSetUp {
[self.view addSubview:self.pagingScrollView];
UIView *lastView = nil;
NSInteger arrayCount = 5;
_subviewsCenterArray = [NSMutableArray array];
for(NSInteger index = 0; index < arrayCount; index++)
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.translatesAutoresizingMaskIntoConstraints = NO;
view.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1];
view.tag = 9999;
view.layer.cornerRadius = 6;
[self.pagingScrollView addSubview:view];
[self.pagingScrollView addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.pagingScrollView
attribute:NSLayoutAttributeTop
multiplier:1
constant:40]];
[self.pagingScrollView addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.pagingScrollView
attribute:NSLayoutAttributeHeight
multiplier:0.80
constant:0]];
[self.pagingScrollView addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.pagingScrollView
attribute:NSLayoutAttributeWidth
multiplier:0.80
constant:0]];
if (lastView == nil && index == 0){
[self.pagingScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-20-[view(==_pagingScrollView)]"
options:0
metrics:nil
views:#{#"view":view, #"_pagingScrollView":_pagingScrollView}]];
} else {
[self.pagingScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[lastView]-20-[view]"
options:0
metrics:nil
views:#{#"lastView":lastView, #"view":view, #"_pagingScrollView":_pagingScrollView}]];
}
if(index == arrayCount-1) {
[self.pagingScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[view]-20-|"
options:0
metrics:nil
views:#{#"view":view}]];
}
[self.view layoutIfNeeded];
lastView = view;
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
[self changeTheCardStatus:scrollView];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self changeTheCardStatus:scrollView];
}
-(void)changeTheCardStatus:(UIScrollView *)scrollView{
for (UIView *view in scrollView.subviews) {
if (view.tag == 9999) {
[_subviewsCenterArray addObject:#(view.center.x)];
}
}
CGFloat currentCenterOffsetX = scrollView.contentOffset.x + CGRectGetWidth(self.view.frame)/2.0;
NSMutableArray *absoluteValueArray = [NSMutableArray array];
NSMutableDictionary *absoluteValueDictionary = [NSMutableDictionary dictionary];
for (int i = 0; i < _subviewsCenterArray.count; i ++) {
float subviewsCenterPointX = [_subviewsCenterArray[i] floatValue];
double absolute = fabs(subviewsCenterPointX - currentCenterOffsetX);
[absoluteValueArray addObject:#(absolute)];
[absoluteValueDictionary setValue:#(subviewsCenterPointX) forKey:[NSString stringWithFormat:#"%f",absolute]];
}
[absoluteValueArray sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
double a = [obj1 doubleValue];
double b = [obj2 doubleValue];
if (a>b) {
return NSOrderedDescending;
}
else if (a<b){
return NSOrderedAscending;
}
else{
return NSOrderedSame;
}
}];
double shortValue = [absoluteValueArray.firstObject doubleValue];
double centerX = [[absoluteValueDictionary objectForKey:[NSString stringWithFormat:#"%f",shortValue]] doubleValue];
[UIView animateWithDuration:0.25 animations:^{
scrollView.contentOffset = CGPointMake(centerX - CGRectGetWidth(self.view.frame)/2.0, 0);
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Of course It's not. The subview of pagingScrollView doesn't have a right width! Also these subviews don's have correct horizontal margin.
First You should correct your setting width code, change the multiplier to 1 and constant to -40. Like this:
[self.pagingScrollView addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.pagingScrollView
attribute:NSLayoutAttributeWidth
multiplier:1
constant:-40]];
Then modify the subview margin, change -20 to -40, like this
[self.pagingScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[lastView]-40-[view]"
options:0
metrics:nil
views:#{#"lastView":lastView, #"view":view, #"_pagingScrollView":_pagingScrollView}]];
Hi I am very new for iOS and I have added a UIView at bottom of MainViewController.
And when I tap on a button that UIView displays like "UIAction sheet" using UIView animations.
And for this I have tried the code below but animations are not applying when I tap on the button.
Please help me.
my code:-
#import "AnimationUIview.h"
#interface AnimationUIview ()
{
UIView * firstView;
NSLayoutConstraint * Bottom;
}
#end
#implementation AnimationUIview
- (void)viewDidLoad {
[super viewDidLoad];
firstView = [[UIView alloc] init];
firstView.backgroundColor = [UIColor lightGrayColor];
firstView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:firstView];
NSDictionary * views = NSDictionaryOfVariableBindings(firstView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[firstView]-0-|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[firstView(100)]" options:0 metrics:nil views:views]];
Bottom = [NSLayoutConstraint constraintWithItem:firstView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1
constant:80];
[self.view addConstraint:Bottom];
}
- (IBAction)buttonAction:(id)sender {
[UIView animateWithDuration:0.5f
delay:0.0f
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
Bottom.constant = -10;
}
completion:nil];
}
#end
#import "AnimationUIview.h"
#interface AnimationUIview () {
UIView * firstView;
NSLayoutConstraint * Bottom;
BOOL isshown;
}
#end
#implementation AnimationUIview
-(void)viewDidLoad {
[super viewDidLoad];
firstView = [[UIView alloc] init];
firstView.backgroundColor = [UIColor lightGrayColor];
firstView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:firstView];
NSDictionary * views = NSDictionaryOfVariableBindings(firstView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[firstView]-0-|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[firstView(100)]" options:0 metrics:nil views:views]];
Bottom = [
NSLayoutConstraint
constraintWithItem:firstView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1
constant:80
];
[self.view addConstraint:Bottom];
isshown=No;
}
- (IBAction)buttonAction:(id)sender {
if (isshown==NO) {
firstview.frame = CGRectMake(0,0, SCREEN_WIDTH, 100);
[UIView animateWithDuration:0.40 animations:^{
firstview.frame = CGRectMake(0, SCREEN_HEIGHT-100, SCREEN_WIDTH, 100);
[firstview setAlpha:0.0f];
} completion:^(BOOL finished) {
}];
isshow=Yes;
} else {
firstview.frame = CGRectMake(0, SCREEN_HEIGHT-100, SCREEN_WIDTH, 100);
[UIView animateWithDuration:0.40 animations:^{
firstview.frame = CGRectMake(0,0, SCREEN_WIDTH, 100);
firstview.alpha = 1.0f;
} completion:^(BOOL finished) {
[firstview setHidden:YES];
}];
isshown=No;
}
#end
Hi i am beginner for auto-layouts and i am inserting "3" textfields and "1" button on scrollview
Here my requirement is according i-phone inches "Top space" must be Adjusting and when i click textfield all fields must be scrolling above keyboard and when i click "return" button in keyboard then scroll must be scrolling as like previous
For this i have tried below code but that is too length code can anybody explain me this concept using short process
my code:-
#import "ViewController10.h"
#interface ViewController10 ()
{
UIScrollView * scrollView;
UITextField * emailTextField;
UITextField * nameTextField;
UITextField * passwword;
UIButton * submit;
NSDictionary * viewsDic;
NSArray * verticalConstraints;
int height;
}
#end
#implementation ViewController10
- (void)viewDidLoad {
[super viewDidLoad];
height = [UIScreen mainScreen].bounds.size.height;
scrollView = [[UIScrollView alloc] init];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollView];
emailTextField = [self createLabelWithText];
emailTextField.delegate = self;
[scrollView addSubview: emailTextField];
nameTextField = [self createLabelWithText];
nameTextField.delegate = self;
[scrollView addSubview: nameTextField];
passwword = [self createLabelWithText];
passwword.delegate = self;
[scrollView addSubview: passwword];
submit = [[UIButton alloc]init];
submit.backgroundColor = [UIColor orangeColor];
[submit setTitle: #"Submit" forState: UIControlStateNormal];
submit.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:submit];
viewsDic = NSDictionaryOfVariableBindings(scrollView,emailTextField,nameTextField,passwword,submit);
//Applying autolayouts for scrolview
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-0-[scrollView]-0-|"]
options:0
metrics:nil
views:viewsDic]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-0-[scrollView]-0-|"]
options:0
metrics:nil
views:viewsDic]];
//Applying autolayouts for textfields and button
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:emailTextField
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:scrollView
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
NSArray * keys = #[#"emailTextField",#"nameTextField",#"passwword",#"submit"];
for (NSString * key in keys) {
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-10-[%#]-10-|",key]
options:0
metrics:nil
views:viewsDic]];
}
if (height == 480.0) {
verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-30-[emailTextField(30)]-130-[nameTextField(30)]-130-[passwword(30)]-60-[submit(30)]-20-|"
options:0
metrics:nil
views:viewsDic];
}
else if (height == 568.0){
verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-50-[emailTextField(30)]-130-[nameTextField(30)]-130-[passwword(30)]-60-[submit(30)]-20-|"
options:0
metrics:nil
views:viewsDic];
}
else if(height == 667.0){
verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-80-[emailTextField(30)]-130-[nameTextField(30)]-130-[passwword(30)]-60-[submit(30)]-20-|"
options:0
metrics:nil
views:viewsDic];
}
[scrollView addConstraints:verticalConstraints];
}
-(UITextField *)createLabelWithText{
UITextField * textfield = [[UITextField alloc] init];
textfield.textColor = [UIColor whiteColor];
textfield.backgroundColor = [UIColor lightGrayColor];
textfield.translatesAutoresizingMaskIntoConstraints = NO;
return textfield;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
scrollView.contentSize = CGSizeMake(320, 700);
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
[scrollView removeConstraints:verticalConstraints];
if (height == 480.0) {
verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-30-[emailTextField(30)]-130-[nameTextField(30)]-130-[passwword(30)]-60-[submit(30)]-20-|"
options:0
metrics:nil
views:viewsDic];
}
else if (height == 568.0){
verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-50-[emailTextField(30)]-130-[nameTextField(30)]-130-[passwword(30)]-60-[submit(30)]-20-|"
options:0
metrics:nil
views:viewsDic];
}
else if(height == 667.0){
verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-80-[emailTextField(30)]-130-[nameTextField(30)]-130-[passwword(30)]-60-[submit(30)]-20-|"
options:0
metrics:nil
views:viewsDic];
}
[scrollView addConstraints:verticalConstraints];
return YES;
}
#end
try masonry,it can reduce the code and it is easier for you to maintain and understand
https://github.com/SnapKit/Masonry
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?
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.