UITableView viewForHeaderInSection UIView animation issue - ios

I have a custom UIView that has two labels, one of which is animated (it blinks like a cursor and looks quite fly). This view works fine EXCEPT when I try to use it for a tableView's header; the animation doesn't repeat even though I specify UIViewAnimationOptionRepeat.
My class:
#implementation HXTEST {
UILabel *cursorLabel;
}
#pragma mark - inits
- (id) initForLabel:(UILabel *)forLabel {
self = [super init];
if (self) {
self.translatesAutoresizingMaskIntoConstraints = NO;
CGRect abba = [forLabel.text boundingRectWithSize:forLabel.frame.size
options:NSStringDrawingUsesFontLeading
attributes:#{ NSFontAttributeName : forLabel.font}
context:[NSStringDrawingContext new]];
float width = CGRectGetWidth(abba) * 1.005f;
self->cursorLabel = [UILabel new];
self->cursorLabel.textColor = forLabel.textColor;
self->cursorLabel.font = forLabel.font;
self->cursorLabel.text = #"▏";
self->cursorLabel.adjustsFontSizeToFitWidth = forLabel.adjustsFontSizeToFitWidth;
self->cursorLabel.minimumScaleFactor = forLabel.minimumScaleFactor;
self->cursorLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:forLabel];
[self addSubview:self->cursorLabel];
[self addConstraint:[NSLayoutConstraint constraintWithItem:forLabel
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeft
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:forLabel
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0f
constant:width]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:forLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:forLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self->cursorLabel
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:forLabel
attribute:NSLayoutAttributeTrailing
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self->cursorLabel
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.f
constant:forLabel.font.pointSize]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self->cursorLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1.f
constant:0.f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self->cursorLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1.f
constant:0.f]];
}
[UIView animateWithDuration:1.f
delay:0.f
options:UIViewAnimationOptionRepeat
animations:^{
self->cursorLabel.alpha = 1.f;
self->cursorLabel.alpha = 0.f;
}
completion:nil];
return self;
}
#end
Is there something about tableView headers and their presentation? Is there some other combination of UIViewAnimationOptions I should consider? Instead of automatically starting the animation block should I trigger it off some event like the headerView's appearance or some such?

Aha! Although [UIView areAnimationsEnabled] defaults to TRUE, it was for some reason FALSE. I forced it with
[UIView setAnimationsEnabled:YES];
before the animation block and all works now! I don't know why it was off...

Try like this using UIViewAnimationOptionAutoreverse option as well:
void (^animationLabel) (void) = ^{
blinkLabel.alpha = 0;
};
void (^completionLabel) (BOOL) = ^(BOOL f) {
blinkLabel.alpha = 1;
};
NSUInteger opts = UIViewAnimationOptionAutoreverse |
UIViewAnimationOptionRepeat;
[UIView animateWithDuration:1.f delay:0 options:opts
animations:animationLabel completion:completionLabel];
Hope it helps!

Related

iOS: update constraints programmatically

I have this code to update constraints for a UITextFiled
- (void)updateUIOnePassword {
NSLayoutConstraint *fullTextField = [NSLayoutConstraint constraintWithItem:self.passwordTextField attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.userIdTextField attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f];
NSLayoutConstraint *cutTextField = [NSLayoutConstraint constraintWithItem:self.passwordTextField attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.userIdTextField attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-60.0f];
if ([self isOnepasswordAvailable]) {
self.onepasswordButton.alpha = 1.0f;
[self.view removeConstraint:fullTextField];
[self.view addConstraint:cutTextField];
} else {
self.onepasswordButton.alpha = 0.0f;
[self.view addConstraint:fullTextField];
[self.view updateConstraints];
}
[self.view setNeedsUpdateConstraints];
[self.view layoutIfNeeded];
}
when isOnepasswordAvailable is TRUE at start, it works fine, after when I delete OP app and isOnepasswordAvailable is FALSE works well again, but when I enter again in isOnepasswordAvailable when id TRUE the constraints don't work fine anymore and I have some warning in the consolle.
Do you know why?
Thanks
Though I always prefer having an IBOutlet to constraint, you have created a constraint programmatically I believe there must be a good reason for that :)
Couple of issues I noticed,
1> I checked both of your constraints, only thing those constraints vary is in their constant values. I believe you dont have to create two different constraint and add and remove them based on condition. Looks very much complicated.
you can have a property named
#property (nonatomic,strong) NSLayoutConstraint *textFieldConstraint;
and in viewWillAppear
if ([self isOnepasswordAvailable]) {
self.textFieldConstraint = [NSLayoutConstraint constraintWithItem:self.passwordTextField attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.userIdTextField attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f];
}
else {
self.textFieldConstraint = [NSLayoutConstraint constraintWithItem:self.passwordTextField attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.userIdTextField attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-60.0f];
}
[self.view addConstraint:self.textFieldConstraint];
[self.view layoutIfNeeded];
2> Update the method updateUIOnePassword as
- (void)updateUIOnePassword {
if ([self isOnepasswordAvailable]) {
self.onepasswordButton.alpha = 1.0f;
self.textFieldConstraint.constant = 0.0f;
} else {
self.onepasswordButton.alpha = 0.0f;
self.textFieldConstraint.constant = -0.60f;
}
[self.view layoutIfNeeded];
}
This should do the job :) Have look buddy :)
- (void)updateUIOnePassword {
NSLayoutConstraint *fullTextField = [NSLayoutConstraint constraintWithItem:self.passwordTextField attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.userIdTextField attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f];
NSLayoutConstraint *cutTextField = [NSLayoutConstraint constraintWithItem:self.passwordTextField attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.userIdTextField attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-60.0f];
if ([self isOnepasswordAvailable]) {
self.onepasswordButton.alpha = 1.0f;
[self.view removeConstraint:fullTextField]; //Invalid statement
[self.view addConstraint:cutTextField];
} else {
self.onepasswordButton.alpha = 0.0f;
[self.view addConstraint:fullTextField];
[self.view updateConstraints];
}
[self.view setNeedsUpdateConstraints];
[self.view layoutIfNeeded];
}
You have an invalid statement. - updateUIOnePassword() gets called fullTextField is not have added as constrain and its just an allocation.
meaning you are trying to remove the object which does not present in the array (Array of constraints)
Now my suggestion is, Make a class level instance of cutTextField and fullTextField add them only once.
when you don't need it
[fullTextField setActive:NO];
When you need to modify
[fullTextField setActive:YES]; //if already set to NO
[fullTextField setConstant:100];

Instance variable used while 'self' is not set to the result of [(super or self) init…]

My Code :
- (instancetype)initWithSender:(UIView*)sender withSuperView:(UIView*)superView withItems:(NSMutableArray*)items
{
self = [CustomDropdownView loadInstanceFromNibWithiPad:NO];
if (self) {
self.frame = CGRectZero;
[self.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[self.layer setBorderWidth:1.0];
CGRect positionInSuper = [superView convertRect:sender.frame fromView:sender.superview];
float height = superView.frame.size.height - positionInSuper.origin.y;
if (height > 200.0) {
// height = 200.0;
}
[superView addSubview:self];
self.translatesAutoresizingMaskIntoConstraints = NO;
self.constLeading = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:positionInSuper.origin.x];
self.constTop = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superView attribute:NSLayoutAttributeTop multiplier:1.0 constant:positionInSuper.origin.y + sender.frame.size.height];
self.constWidth = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:sender.frame.size.width];
self.constHeight = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:0];
[superView addConstraints:#[self.constLeading, self.constTop]];
[self addConstraints:#[self.constWidth, self.constHeight]];
[self layoutIfNeeded];
self.arrItems = [[NSMutableArray alloc]initWithArray:items];
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([DropDownTableViewCell class]) bundle:nil] forCellReuseIdentifier:NSStringFromClass([DropDownTableViewCell class])];
[self.tableView reloadData];
}
return self;
}
The first line
self = [CustomDropdownView loadInstanceFromNibWithiPad:NO];
is very problematic. You should only assign the result of another init method, usually [super init]. Change this to a class method.
By the way, that's what the error message says.

All images of UIScrollView are getting placed in the beginning

I am new to iOS programming. I want to generate all the controls using coding and then apply constraints to achieve autosize feature. I had achieved almost my requirement except for one problem and that is all images of my UIScrollView are getting placed at very beginning and rest of the UIScrollView stays empty. I think I am having some sort of problem with my constraints and currently I am not able to resolve it.
This is my code
self.bgView.image = [UIImage imageNamed:#"bg.png"];
NSDictionary *viewDictionary = #{#"bgImage":self.bgView,#"scrollView":self.scrollView};
NSDictionary *position = #{#"vSpacing":#0,#"hSpacing":#0};
//here I had specified the size of the background image corresponding to the view
NSArray *constraint_POS_H = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-hSpacing-[bgImage]-hSpacing-|" options:0 metrics:position views:viewDictionary];
NSArray *constraint_POS_V = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-vSpacing-[bgImage]-vSpacing-|" options:0 metrics:position views:viewDictionary];
[self.view addConstraints:constraint_POS_H];
[self.view addConstraints:constraint_POS_V];
//here I am specifying the size of scroll view
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:self.scrollView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:self.bgView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:self.scrollView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.bgView
attribute:NSLayoutAttributeHeight
multiplier:0.5
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:self.scrollView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.bgView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:self.scrollView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.bgView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
//self.view.autoresizesSubviews = YES;
self.scrollView.pagingEnabled = YES;
NSInteger numberOfViews = photoArray.count;
for (int i=0; i < numberOfViews; i++) {
CGFloat myOrigin = i * self.view.frame.size.width;
NSLog(#"self.view.frame.size.width : %f",self.view.frame.size.width);
UIView *myView = [[UIView alloc]initWithFrame:CGRectMake(myOrigin, 0, self.view.frame.size.width, self.scrollView.frame.size.height)];
[myView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:myView];
//here I am specifying the size of uiview
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:myView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:self.scrollView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:myView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0.0]];
//here I am specifying the position of uiview
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:myView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:myView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
UIImageView *photos = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, myView.frame.size.width, self.scrollView.frame.size.height)];
//self.photos = [UIImageView new];
[photos setTranslatesAutoresizingMaskIntoConstraints:NO];
photos.image = [photoArray objectAtIndex:i];
[myView addSubview:photos];
//here I am specifying the size of image view within scroll view
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:photos
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:myView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:photos
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0.0]];
//here I am specifying the position of the image view
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:photos
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:photos
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:myView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
self.scrollView.delegate = self;
[self.scrollView addSubview:myView];
NSLog(#"self.myView.frame.size.width : %f",myView.frame.size.width);
}
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width * numberOfViews,
self.scrollView.frame.size.height);
CGPoint scrollPoint = CGPointMake(0, 0);
[self.scrollView setContentOffset:scrollPoint animated:YES];
[self.view addSubview:self.scrollView];
you can easily solve it by just using reset to suggested constraints in storyboard.First select viewController and then press right bottom menu and select reset to suggested constraints in All views tab
This worked for me.

Implement child UIView with fixed aspect ratio to aspect fit

I have some issue with autolayout.
We have ViewController with root view and child view.
Child view have fixed aspect ratio.
I need to fit child view in parent while rotation.
Also chid view should be centered.
Like on a picture:
I have this code:
- (void)viewDidLoad
{
[super viewDidLoad];
UIView * v = [UIView new];
v.backgroundColor = [UIColor redColor];
v.translatesAutoresizingMaskIntoConstraints = NO;
v.tag = 100;
[self.view addSubview:v];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[v]|"
options:0
metrics:nil
views:#{#"v":v}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[v]|"
options:0
metrics:nil
views:#{#"v":v}]];
for (NSLayoutConstraint *c in self.view.constraints) {
[c setPriority:800];
}
NSLayoutConstraint *c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:v
attribute:NSLayoutAttributeWidth
multiplier:0.8
constant:0.];
[c setPriority:1000];
[v addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0.];
[c setPriority:1000];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0.];
[c setPriority:1000];
[self.view addConstraint:c];
}
And it's not working, it's shrinks outside superview in landscape.
I've made it work with the following constraints:
- (void)viewDidLoad
{
[super viewDidLoad];
UIView * v = [UIView new];
v.backgroundColor = [UIColor redColor];
v.translatesAutoresizingMaskIntoConstraints = NO;
v.tag = 100;
[self.view addSubview:v];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(>=0)-[v]-(>=0)-|"
options:0
metrics:nil
views:#{#"v":v}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(>=0)-[v]-(>=0)-|"
options:0
metrics:nil
views:#{#"v":v}]];
NSLayoutConstraint *c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
[c setPriority:800];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0];
[c setPriority:800];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:v
attribute:NSLayoutAttributeWidth
multiplier:0.8
constant:0.];
[c setPriority:1000];
[v addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0.];
[c setPriority:1000];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0.];
[c setPriority:1000];
[self.view addConstraint:c];
}
Screenshots:

ios AutoLayout issue for flexible width?

I think this is an issue of autolayout.
I create a view, and create some subviews in it.
The content view contains the subviews, and the subviews lays all in one line.
I think I didn't do something wrong, but the content view 's frame always incorrect.
like this:
2013-08-29 14:13:34.688 AutoLayoutBugTest[4658:c07] pV_content.frame {{0, 208}, {319, 44}}
The content view's width is 319 but not 320, change the 'cnt' param in viewDidLoad function, the frame may worse.
code like this:
#interface ViewController ()
#property (nonatomic, strong) UIView *pV_content;
#property (nonatomic, strong) NSMutableArray *Arr_views;
#end
#implementation ViewController
- (void)removeConstraintForCustomView:(UIView *)customView
fromView:(UIView *)superView
{
NSMutableArray *pArr_constraint = [NSMutableArray array];
for (NSLayoutConstraint *constraint in superView.constraints) {
if ([constraint.firstItem isEqual:customView]) {
[pArr_constraint addObject:constraint];
}
}
[superView removeConstraints:pArr_constraint];
pArr_constraint = nil;
}
- (void)constraintCustomView:(UIView *)customView
matchWidthOfView:(UIView *)superView
withHeight:(CGFloat)height
{
[self removeConstraintForCustomView:customView fromView:superView];
customView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint_y = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeCenterY
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_y];
NSLayoutConstraint *constraint_height = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeHeight
multiplier:0.f
constant:height];
[superView addConstraint:constraint_height];
NSLayoutConstraint *constraint_left = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeLeft
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_left];
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_width];
}
- (void)constraintCustomView:(UIView *)customView
matchWidthPercentOfView:(UIView *)superView
boxCount:(int)boxCount
boxIndex:(int)boxIndex
{
[self removeConstraintForCustomView:customView fromView:superView];
customView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint_top = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeTop
multiplier:1.f
constant:customView.frame.origin.y];
[superView addConstraint:constraint_top];
constraint_top.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_height = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeHeight
multiplier:0.f
constant:customView.frame.size.height];
[superView addConstraint:constraint_height];
constraint_height.priority = UILayoutPriorityFittingSizeLevel;
if (boxCount == 1) {
NSLayoutConstraint *constraint_percent_x = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeCenterX
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_percent_x];
constraint_percent_x.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:1.f
constant:-4.f];
[superView addConstraint:constraint_width];
constraint_width.priority = UILayoutPriorityFittingSizeLevel;
}
else {
if (boxIndex == 0) {
NSLayoutConstraint *constraint_left = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeLeft
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_left];
constraint_left.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:(2.f / (CGFloat)(2 * boxCount + 1))
constant:-2.f];
[superView addConstraint:constraint_width];
constraint_width.priority = UILayoutPriorityFittingSizeLevel;
}
else if (boxIndex == boxCount - 1) {
NSLayoutConstraint *constraint_right = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeRight
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_right];
constraint_right.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:(2.f / (CGFloat)(2 * boxCount + 1))
constant:-2.f];
[superView addConstraint:constraint_width];
constraint_width.priority = UILayoutPriorityFittingSizeLevel;
}
else {
NSLayoutConstraint *constraint_percent_x = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeCenterX
multiplier:(((CGFloat)(2 * boxIndex + 1)) / (CGFloat)boxCount)
constant:0.f];
[superView addConstraint:constraint_percent_x];
constraint_percent_x.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:(2.f / (CGFloat)(2 * boxCount + 1))
constant:-2.f];
[superView addConstraint:constraint_width];
constraint_width.priority = UILayoutPriorityFittingSizeLevel;
}
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
self.pV_content = [[UIView alloc] initWithFrame:CGRectMake(0.f,
0.f,
self.view.frame.size.width,
44.f)];
self.pV_content.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:self.pV_content];
[self constraintCustomView:self.pV_content
matchWidthOfView:self.view
withHeight:44.f];
int cnt = 5;
for (int i = 0; i < cnt; i++) {
UIView *pV_sub = [[UIView alloc] initWithFrame:CGRectMake(0.f,
5.f,
30.f,
35.f)];
pV_sub.backgroundColor = [UIColor redColor];
[self.pV_content addSubview:pV_sub];
[self constraintCustomView:pV_sub
matchWidthPercentOfView:self.pV_content
boxCount:cnt
boxIndex:i];
}
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
NSLog(#"pV_content.frame %#", NSStringFromCGRect(self.pV_content.frame));
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
#end
From guide:
Constraints are of the form "view1.attr1 view2.attr2 * multiplier + constant". If the constraint you wish to express does not have a second view and attribute, use nil and NSLayoutAttributeNotAnAttribute.
And secondary: Try use
constraintsWithVisualFormat:options:metrics:views:
For example if you have a view testView:
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[testView]|" options:0 metrics:0 views:#{#"testView":self.testView}]];
in constraintsWithVisualFormat method you can set priority and variants like:#"H:|-(0#100)-[testView(100)]-(0#100)-|". This testView have hight priority, because priority parameter not set, but 2 constraints from left and right size to superview have priority 100, and your view testView not change self frame.
You can set format like this: [testView(50,100)] in this your code means: "testView widht can be 50 points or 100.
Read this guide

Resources