I create a uicollectionview programmatically, and I want to add auto layout constraint on the collection view so that I can change the frame later. But the following code is not work.
I am trying to initialize the collectionview like this:
self.rootCollectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 100, self.bounds.size.width, self.bounds.size.height - 100) collectionViewLayout:[[UICollectionViewFlowLayout alloc]init]];
self.rootCollectionView.dataSource = self;
self.rootCollectionView.delegate = self;
self.rootCollectionView.backgroundColor = [UIColor clearColor];
[self addSubview:self.rootCollectionView];
[self.rootCollectionView registerClass:[CASlideSwitchViewCell class] forCellWithReuseIdentifier:#"CASlideSwitchViewCell"];
self.topConstraint = 100;
float topCon = self.topConstraint;//self.topConstraint is a CGFloat property,
UICollectionView * cv = self.rootCollectionView;
cv.translatesAutoresizingMaskIntoConstraints = NO;
NSArray * constraintArray = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[cv]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(cv)];
NSArray *constraintArray2 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-topCon-[cv]-0-|" options:0 metrics:#{#"topCon":#(topCon)} views:NSDictionaryOfVariableBindings(cv)];
[self addConstraints:constraintArray];
[self addConstraints:constraintArray2];
then after I receive the data, I am trying to change topConstraint based on the data. Like this:
if (number <= 1) {
self.topScrollView.hidden = YES;
self.topConstraint = 0;
}else{
self.topScrollView.hidden = NO;
self.topConstraint = 100;
}
[self updateConstraints];
[self.rootCollectionView.collectionViewLayout invalidateLayout];
[self.rootCollectionView reloadData];
However, the top margin of the UICollectionView is always 100.
Do I miss something? Or it is not right to add auto layout like that?
The self.topConstraint is a float not a NSLayoutConstraint so you can not update the constraint. You can instead of using
NSArray *constraintArray2 = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-topCon-[cv]-0-|" options:0 metrics:#{#"topCon":#(topCon)} views:NSDictionaryOfVariableBindings(cv)];
You should use
NSLayoutConstraint *topLayoutContraint = [NSLayoutConstraint constraintWithItem:cv
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:100];
NSArray *constraintArray2 = #[
topLayoutContraint,
[NSLayoutConstraint constraintWithItem:cv
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0]
];
then you can
if (number <= 1) {
self.topScrollView.hidden = YES;
topLayoutContraint.constant = 0;
} else {
self.topScrollView.hidden = NO;
topLayoutContraint.constant = 100;
}
[self setNeedsLayout];
[self.rootCollectionView reloadData];
Related
I have a ViewController that adds an UIView, SpeciesImageView as a subview in viewDidLoad and set constraints in viewWillLayoutSubviews.
SpeciesImageView does not have a nib file. When we create speciesImageView in viewDidLoad, it calls initWithFrame in SpeciesImageView class.
This works fine (in both landscape and portrait) until the phone rotates. I tried setting the constraints as speciesImageView.frame.size.width, but that doesn't work because initWithFrame isn't called when the orientation changes, so the height/width of the speciesImageView remains unchanged.
On the other hand, using screenRect doesn't change the actual size of the UIView, it changes its size within the superview. So in other words, I haven't found a way to change the size of the actual speciesImageView on orientation change.
And for reasons lost to me, it gets completely messed up when you rotate it back to the original position.
- (void)viewDidLoad
{
self.tabBarController.tabBar.hidden=YES;
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
self.navigationController.navigationBar.hidden = NO;
//self.navigationController.navigationBar.translucent = YES;
UIImage *plantinfo;
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
plantinfo = [UIImage imageNamed:#"plantinfo_frame.png"];
} else {
plantinfo = [UIImage imageNamed:#"plantinfo.png"];
}
UIBarButtonItem *tempButton = [[UIBarButtonItem alloc] initWithImage:plantinfo
style:UIBarButtonItemStylePlain
target:self
action:#selector(toggleText:)];
self.navigationItem.rightBarButtonItem = tempButton;
[tempButton release];
self.title = theSpecies.scientificName;
//[self.navigationItem.backBarButtonItem setTitle:#""];
self.navigationItem.backBarButtonItem.title = #"";
infoViewSegmentedControl.backgroundColor = [UIColor blackColor];
webView.backgroundColor = [UIColor blackColor];
_activityIndicator.hidden = YES;
[webView setOpaque:YES];
webView.delegate = self;
// Do double justification
[webView loadHTMLString:[self formatHTML:theSpecies] baseURL:nil];
showingInfoView = NO;
//
// Resize containerView, infoview according to iphone 5 screen size.
//
infoView.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;
CGPoint screenOrigin = [[UIScreen mainScreen] bounds].origin;
CGSize viewSize = [[UIScreen mainScreen] bounds].size;
CGPoint origin = infoView.frame.origin;
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
infoView.frame = CGRectMake(screenOrigin.x,
screenOrigin.y + statusBarFrame.size.height,
viewSize.width,
viewSize.height - origin.y - statusBarFrame.size.height);
speciesImageView = [[SpeciesImageView alloc]
initWithFrame:CGRectMake(screenOrigin.x,
screenOrigin.y,
viewSize.width,
viewSize.height)];
} else {
infoView.frame = CGRectMake(screenOrigin.x,
screenOrigin.y,
viewSize.width,
viewSize.height - origin.y - statusBarFrame.size.height);
speciesImageView = [[SpeciesImageView alloc]
initWithFrame:CGRectMake(screenOrigin.x,
screenOrigin.y,
viewSize.width,
viewSize.height - statusBarFrame.size.height)];
}
speciesImageView.delegate = self;
[containerView addSubview:speciesImageView];
managedObjectContext = [(LeafletAppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];
[self parseImageURLArray];
}
-(void)viewWillLayoutSubviews{
if(speciesImageView.window != nil){
CGRect screenRect = [[UIScreen mainScreen] bounds];
speciesImageView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *widthConst = [NSLayoutConstraint
constraintWithItem:speciesImageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:screenRect.size.width];
NSLayoutConstraint *heightConst = [NSLayoutConstraint
constraintWithItem:speciesImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:screenRect.size.height];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint
constraintWithItem:speciesImageView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint
constraintWithItem:speciesImageView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0];
[self.view addConstraints:#[widthConst, heightConst, bottomConstraint, rightConstraint]];
}
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
imageScrollView = [[UIScrollView alloc] initWithFrame:frame];
imageScrollView.delegate = self;
imageScrollView.backgroundColor = [UIColor blackColor];
[self addSubview:imageScrollView];
imageScrollView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *widthConst = [NSLayoutConstraint constraintWithItem:imageScrollView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:imageScrollView.frame.size.width];
NSLayoutConstraint *heightConst = [NSLayoutConstraint constraintWithItem:imageScrollView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:imageScrollView.frame.size.height];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint
constraintWithItem:imageScrollView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0.0];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint
constraintWithItem:imageScrollView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];
[self addConstraints:#[widthConst, heightConst, bottomConstraint, rightConstraint]];
}
return self;
}
If you want your views to adjust to the size of the superview,
then you need something like this (set the margin to whatever you like):
CGFloat margin = 0;
NSString * visualFormatH = [NSString stringWithFormat:#"|-(%f)-[speciesImageView]-(%f)-|", margin, margin];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualFormatH
options:0
metrics:Nil
views:#{#"speciesImageView": speciesImageView}]];
NSString * visualFormatV = [NSString stringWithFormat:#"V:|-(%f)-[speciesImageView]-(%f)-|", margin, margin];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualFormatV
options:0
metrics:Nil
views:#{#"speciesImageView": speciesImageView}]];
Now speciesImageView will adjust its frame whenever the superview frame changes.
Here is a generic example:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView * sampleView = [UIView new];
sampleView.backgroundColor = [UIColor redColor];
sampleView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:sampleView];
CGFloat margin = 0;
NSString * visualFormatH = [NSString stringWithFormat:#"|-(%f)-[sampleView]-(%f)-|", margin, margin];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualFormatH
options:0
metrics:Nil
views:#{#"sampleView": sampleView}]];
NSString * visualFormatV = [NSString stringWithFormat:#"V:|-(%f)-[sampleView]-(%f)-|", margin, margin];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualFormatV
options:0
metrics:Nil
views:#{#"sampleView": sampleView}]];
}
Auto Layout Getting Started
Auto Layout Visual Format Documentation
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}]];
I am trying to draw a 15*15 grid in Objective-C. The grid colour is blue which is like making the board of the "Snake" game in NOKIA.
I've tried using the for loop to create subviews but it seems not working, I looked over the internet and most of them are using UIImageView to make the grid, is there any solution for making a 15*15 grid with for loop or I have to use the UIImageView method?
- (void)viewDidLoad {
[super viewDidLoad];
int i;
int row = 0;
int col = 0;
int firstColor=0;
if ([[UIDevice currentDevice] userInterfaceIdiom]== UIUserInterfaceIdiomPhone){
cellWidth = 23;
CellHeight= cellWidth;
topY=230-4*CellHeight;
leftX=110-4*cellWidth;
}else{
cellWidth=46;
CellHeight=cellWidth;
topY=500-4*CellHeight;
leftX=384-4*cellWidth;
}
UIView *viewA = [[UIView alloc]initWithFrame:CGRectMake(0, 30, 414, 434)];
viewA.backgroundColor = [UIColor blackColor];
[self.view addSubview:viewA];
for (int row = 0; row < rows; row = row++ ){
for(int r = 0; r <= 414; r = r + 23){
UIView *viewB = [[UIView alloc]initWithFrame:CGRectMake(r,5,23,23)];
viewB.backgroundColor = [UIColor blueColor];
[viewA addSubview:viewB];}}
col=col+1;
firstColor=1-firstColor;
if (col>18){
row=row+1;
firstColor=1-firstColor;
col=0;
}
If using iOS 9, the stacked view handles laying out a grid of view nicely:
NSInteger n = 15;
UIStackView *rowView = [[UIStackView alloc] init];
rowView.translatesAutoresizingMaskIntoConstraints = false;
rowView.axis = UILayoutConstraintAxisHorizontal;
rowView.distribution = UIStackViewDistributionFillEqually;
[self.view addSubview:rowView];
for (NSInteger row = 0; row < n; row++) {
UIStackView *columnView = [[UIStackView alloc] init];
columnView.translatesAutoresizingMaskIntoConstraints = false;
columnView.axis = UILayoutConstraintAxisVertical;
columnView.distribution = UIStackViewDistributionFillEqually;
[rowView addArrangedSubview:columnView];
for (NSInteger col = 0; col < n; col++) {
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor colorWithRed:arc4random_uniform(256) / 255.0
green:arc4random_uniform(256) / 255.0
blue:arc4random_uniform(256) / 255.0
alpha:1.0];
view.translatesAutoresizingMaskIntoConstraints = false;
view.layer.borderColor = [UIColor blackColor].CGColor;
view.layer.borderWidth = 0.5;
[columnView addArrangedSubview:view];
// make it it the width of the column stack view, and 1/n of the height of the column stack view
[columnView addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:columnView attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
[columnView addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:columnView attribute:NSLayoutAttributeHeight multiplier:1.0 / (CGFloat)n constant:0]];
}
}
// make it square
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:rowView attribute:NSLayoutAttributeHeight multiplier:1 constant:0]];
// center it
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
// ensure it never exceeds 80% of the width or height of super view
NSLayoutConstraint *maxWidthConstraint = [NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:0.8 constant:0];
NSLayoutConstraint *maxHeightConstraint = [NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:0.8 constant:0];
[self.view addConstraints:#[maxWidthConstraint, maxHeightConstraint]];
// But have it take up 80% of either the width or height of super view
NSLayoutConstraint *preferredWidthConstraint = [NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:0.8 constant:0];
preferredWidthConstraint.priority = 900;
NSLayoutConstraint *preferredHeightConstraint = [NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:0.8 constant:0];
preferredHeightConstraint.priority = 900;
[self.view addConstraints:#[preferredWidthConstraint, preferredHeightConstraint]];
That yields:
If targeting earlier iOS versions, you can add build grid yourself, but it entails adding more constraints to make everything layout properly.
One way is to use bezierPath for drawing the custom view. If you need 3*3 grid layout, you need 9 bezier paths!!!!
YOu can achieve this kind of result by using bezier path:
YOu can even enter the rows/cols you need:
declare the properties in your view .h file:
#property (assign) int row;
#property (assign) int col;
and you can call the view from your view controller using:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
testView *tv = [[testView alloc]initWithFrame:CGRectMake(30, 50, 100, 100)];
tv.row = 3;
tv.col = 4;
[self.view addSubview:tv];
}
Here I assumed grid cell size as 20x20
-(void)drawRect:(CGRect)frame {
int x = 0, y = 0;
for (int i = 1; i <= _row*_col; i++) {
UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect: CGRectMake(CGRectGetMinX(frame) + x + 27, CGRectGetMinY(frame) + y + 13, 20, 20)];
[UIColor.grayColor setFill];
[rectanglePath fill];
[UIColor.blackColor setStroke];
rectanglePath.lineWidth = 1;
[rectanglePath stroke];
x = x + 20;
if (i%_row == 0) {
x = 0;
y = y + 20;
}
}
}
You can playaround with the grid colors too!!!
I am adding 3 UITextfields and 1 UIButton on my scrollview.
My main requirement is when I click on UITextfield scroll must scroll up-to all fields visible to user above keyboard.
And when I click return button on keyboard scroll must scroll by default what in set for scrollview contentSize using auto-layouts.
my code:
#interface ViewController10 ()
{
UIScrollView * scrollView;
UITextField * emailTextField;
UITextField * nameTextField;
UITextField * passwword;
UIButton * submit;
}
#end
#implementation ViewController10
- (void)viewDidLoad {
[super viewDidLoad];
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];
NSDictionary * 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]];
}
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-30-[emailTextField(30)]-130-[nameTextField(30)]-130-[passwword(30)]-60-[submit(30)]-20-|"
options:0
metrics:nil
views:viewsDic]];
}
-(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];
return YES;
}
Please check this awsome tutorial , it is definetly helpfull for you.
**
Using UIScrollView with Auto Layout in iOS
**
as said in blog you need to set constrain in this way when you are using autolayout.
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.contentView
attribute:NSLayoutAttributeLeading
relatedBy:0
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0];
[self.view addConstraint:leftConstraint];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.contentView
attribute:NSLayoutAttributeTrailing
relatedBy:0
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0];
[self.view addConstraint:rightConstraint];
change value and name according to your requirement.
When keyBoards is appears .
CGRect frame = currentActiveView.frame; // your scrollview frame
frame.size.height = SCREEN_HEIGHT - 216 - keyboardAccesssory.frame.size.height;
currentActiveView.frame = frame;
[yourScrollView setContentSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT)];
When keyboard is resign ..
CGRect frame = currentActiveView.frame; // your scrollview frame
frame.size.height = SCREEN_HEIGHT;
currentActiveView.frame = frame;
[yourScrollView setContentSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT)];
You need to play with the frame of the view.
Move the frame above keyboard when keyboard is shown whereas reset its position when keyboard is hidden.
You need to do it programmatically.
You can also go through Apple's Programming guide. https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html#//apple_ref/doc/uid/TP40009542-CH5-SW3
I'm trying to understand auto layout better and I created some static methods that can help me out. Now I'm trying to setup an array of views in like a tableview structure (in rows). This works kinda.
See here my problem:
To achieve this I use this code:
//In the update constraints method
UIView *view1 = [self createView];
view1.backgroundColor = [UIColor redColor];
UIView *view2 = [self createView];
view2.backgroundColor = [UIColor yellowColor];
[self addSubview:view1];
[self addSubview:view2];
[self addConstraints:[DXVFL row:#[view1, view2] inView:self]];
//The row method
+ (NSArray *) row:(NSArray const *)views inView:(UIView const *)superview {
NSMutableArray *constraints = [NSMutableArray new];
CGFloat multiplier = 1.f / [views count];
UIView *prev = nil;
for (UIView *view in views) {
if (!view.hidden) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeWidth multiplier:1.f constant:0.f]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeHeight multiplier:multiplier constant:0.f]];
if (prev) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prev attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]];
}
prev = view;
}
}
return [constraints copy];
}
So this part works (I guess). But when I want to split the yellow view again in rows. The views are always added into the top region?
In the update constraints method I do this:
UIView *view1 = [self createView];
view1.backgroundColor = [UIColor redColor];
UIView *view2 = [self createView];
view2.backgroundColor = [UIColor yellowColor];
[self addSubview:view1];
[self addSubview:view2];
UIView *view3 = [self createView];
UIView *view4 = [self createView];
[view2 addSubview:view3];
[view2 addSubview:view4];
[self addConstraints:[DXVFL row:#[view1, view2] inView:self]];
[view2 addConstraints:[DXVFL row:#[view3, view4] inView:view2]];
But I want those two rows in the bottom? What am I doing wrong?
Off the top of my head:
You need to add a constraint to tell it to align the view to the top of the superview. At the moment, you just set the height and width but you don't tell it where to put its top edge.
Try changing your code to this:
if (!prev) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.f constant:0.f]];
} else {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prev attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]];
}