I would like ButtonA to stay where it is, and ButtonB to move a distance x vertically downward away from it.
// Using Autolayout.
UIButton *buttonA, *buttonB;
UIView *fatherView; // The superview of buttonA and B.( The view where they are inside).
CGFloat distance;
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:buttonB attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:buttonA attribute:NSLayoutAttributeBottom multiplier:1 constant:distance];
[fatherView addConstraint:constraint];
// Without autolayout, maybe more easy.
buttonB.center = CGPointMake(buttonA.center.x, buttonA.center.y + distance);
Related
I have a view like below which has auto layout set in xibs.
Now I need to add a error notification, which will animate from top and the existing views will shift down, like this image below.
I know I can do this easily by simply adding this error view in my existing view controller and managing its height constraints. But I have a couple of other views where I need to re-use this error view. So, now I have created a custom view for this error view. Now my main problem is adding this to my mainview programatically with autolayout. So I need to add the blue error view in my self.view and remove the top layout constraint of the green view and set its top to the blue error view. Make sense? Below is my code for error view and adding it to self.view. But even that doesn't work, am I doing anything wrong here. Any help is appreciated.
-(id)initWithdelegate:(id)parentSelf ForView:(UIView *)parentView
{
if (self = [super initWithFrame:CGRectMake(0, 0, 100, 100)])
{
// Initialization code
self=(ErrorView*)[[[NSBundle mainBundle] loadNibNamed:#"ErrorView" owner:nil options:nil]objectAtIndex:0];
self.delegate=parentSelf;
[parentView addSubview:self];
self.hidden = YES;
[self setConstraintsToParentView:parentView];
}
return self;
}
-(void)setConstraintsToParentView:(UIView *)parentView
{
[parentView setTranslatesAutoresizingMaskIntoConstraints:NO];
//Setting width equal to parentview
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:parentView
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
//Setting fixed height of 50
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:50]];
//Setting x pos to center
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:parentView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
//Setting top position to self.view with constant 20
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:parentView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:20]];
}
I'm calling the errorView like this from my viewcontroller
myErrorView = [[ErrorView alloc]initWithdelegate:self ForView:self.view];
you can use identifier propertiy of constraints
NSArray *ArrayConstraint = yorlableorView.constraints;
for (NSLayoutConstraint *ob in ArrayConstraint)
{
if ([ob.identifier isEqualToString:#"yourIdentifier"])
{
ob.constant = 0 ;
// set your constant you want
}
}
Could you just add the error view as the top view with a height of 0 and then change the height constraint constant when you want to display it? You can animate this and it will simulate it pushing everything down, however with this approach it won't look like it is coming down from the top of the screen.
If you're happy with this approach you could just add a container view to your view with the buttons and tableview, then after you initialise the error view from the xib just assign it to the container, this will save you having to pass the parent view, adding it as a subview and adding the constraints programmatically in your error view class.
Let me know if need more detail or a concrete example. Hope this helps, good luck. Also just as an aside, you could look into Masonry, it makes adding constraints programmatically much easier.
I have a collection view pinned to its superview bottom, left, and right edges and a text field pinned to superview top, left, and right. The collection view's height is increased in updateConstraints from the bottom up with a height constraint based on its content size as more items are added to it.
I'd like the collection view height to grow but not exceed the
bottom of the textField above it with an inequality constraint on the
collection view's top edge. Here's what I've tried:
self.topResistanceConstraint = [NSLayoutConstraint constraintWithItem:self.collectionView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:self.textField
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0];
[self addConstraint:self.topResistanceConstraint];
CGSize size = self.collectionView.collectionViewLayout.collectionViewContentSize;
self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.collectionView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:size.height];
[self addConstraint:self.heightConstraint];
This results in unsatisfiable constraints, and recovers (and actually appears to work), but it's not a good solution and doesn't work if the layout needs to adapt to a keyboard appearing or disappearing. Any suggestions how to create constraints or priorities to get this to work without breaking constraints?
After some trial and error, simply setting the heightConstraint to low priority works well. The topResistanceConstraint's priority is required, and prevents the collection view's top from exceeding the bottom of the text field.
self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.collectionView attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:size.height];
// set a low priority on height
self.heightConstraint.priority = UILayoutPriorityLow;
[self addConstraint:self.heightConstraint];
The preferred solution for this problem is to create a height and top constraint
(top constrains related by "NSLayoutRelationGreaterThanOrEqual") for the collectionView in the storyboard and create the outlet for both.
After that get the collectionView item count and than dynamically calculate the height of the collectionView as below
NSInteger count = 5;
CGFloat collectionViewHeight = count/2 * cellHeight; // for collectionView with two(2) columns
CGFloat maxCollectionViewHeight = CGRectGetHeight(self.view.frame) - CGRectGetHeight(self.textField.frame) - CGRectGetMaxY(self.textField.frame);
if (collectionViewHeight < maxCollectionViewHeight ) {
self.heightConstraint.constant = collectionViewHeight;
} else {
self.topConstraint.constant = 20; // Min spacing between two views;
}
I have a tableview using auto layout constraints , every thing is working in iOS 7 but when i tested in iOS 8 get me the below warning
Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.
After i made a profound investigations about this issue i found should add the below lines in viewdidload for iOS8 only
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 87;
After that still i get this warning and the height of cell isn't correct which is not take the height from Storyboard
For further info about UITableViewCell find below our constraints for content view cell
-(void) updateConstraints {
[super updateConstraints];
if(!didSetupConstraints ) {
didSetupConstraints = YES;
[self.contentView removeConstraints:self.contentView.constraints];
// Interval Title
//Leading
constraint = [NSLayoutConstraint constraintWithItem:self.intervalTitle attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterX multiplier: 1.0 constant:0.0];
[self.contentView addConstraint:constraint];
//Top
constraint = [NSLayoutConstraint constraintWithItem:self.intervalTitle attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.marketLocationTitle attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0];
[self.contentView addConstraint:constraint];
}
Auto Layout is right on that one. It's impossible to calculate cell's height from .CenterX and .Top for the label. One way to resolve the problem would be removing the existing .CenterX constraint and adding a new .Bottom constraint. That way, Auto Layout could easily calculate cell's height.
I have a subclass of NSScrollView. Within that scrollView's documentView I have a couple of NSViews. Finally, I add an NSView called aView to the documentView.
I want aView to be at the bottom of the documentView as long as there's no scrolling needed. Scrolling is only possible along the y-axis.
If the documentView is too high for the contentView - so that scrolling is needed - I want aView to be displayed at the bottom of the contentView.
This works fine with the code that you see below.
Here's my Problem:
The moment I start to scroll, I want aView to stay at the bottom of the contentView but aView just scrolls with all the other views within documentView.
In other words: I want aView's position to be fixed at the bottom of the visible rect of my scrollView if scrolling is needed and to stick to the bottom of the documentView if the contentView is high enough to show the whole documentView.
Is there a way to do that? Where do I go wrong?
Here's the code in my subclassed NSScrollView:
[documentView addSubview:aView];
aView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *documentAViewBottom = [NSLayoutConstraint constraintWithItem:documentView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:aView attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
documentAViewBottom.priority = NSLayoutPriorityDefaultHigh;
[documentView addConstraint:documentAViewBottom];
NSLayoutConstraint *aViewMaxYEdge = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:aView attribute:NSLayoutAttributeBottom multiplier:1 constant:5];
[self addConstraint:aViewMaxYEdge];
[documentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[aView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(aView)]];
I am kinda oldschool and NSLayoutConstraints don't appeal to me, so here is a alternate proposed manual solution
from your subclass of NSScrollView when you set up the document view,
[self.contentView setPostsBoundsChangedNotification:YES];
then subscribe to the bounds changed
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contentViewDidScroll:)
name:NSViewBoundsDidChangeNotification object:self.contentView];
then in
-(void)contentViewDidScroll
{
double widthOfAView = aView.frame.size.width;
double heightOfAView = aView.frame.size.height;
[aView setFrameOrigin:NSMakePoint(NSMinX(self.contentView.bounds) - widthOfAView, NSMaxY(self.contentView.bounds) - heightOfAView)];
}
All of this assuming your isFlipped is overridden to YES, of course.
I've read some tutorials on using AutoLayout but I just can't seem to figure out how to achieve something that I feel should be incredibly simple. I'm designing an application for both 3.5 and 4 inch iPhone/iPod Touch screens. It's a simple tab bar application with a UITableView filling up the entirety of each tab, like so:
I would like for the UITableView to lock to the edges of the screen, regardless of whether the screen is 3.5 or 4 inches. What I currently have works fine on 4-inch screens, but on 3.5 the UITableView extends beyond the width of the screen.
I've tried reading some AutoLayout tutorials as well as fiddling with Interface Builder constraints, but without success. I would appreciate any help you can provide.
You need to attach the UITableView to all edges of the parent UIView, and then the UITableView will expand or shrink to fill the UIView on the device. This will make it appear to be the proper size on all iDevices, including iPad. As pictured in the screenshot below, you can just tap all the dashed red guides, making sure the margins are set to 0 (touch the sides):
You could also Ctrl + drag left, drag right, drag up, and drag down on the UITableView choosing "Leading Space to Container", "Trailing Space to Container," "Top Space to Top Layout Guide", and "Bottom Space to Bottom Layout" respectively.
Alternatively, you could use the Visual Format Language (VFL) (code for a UIViewController below assumes your UITableView is an auto-#synthesized #property named tableView):
/* Turn off springs/structs */
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
/* Leading and trailing constraints */
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_tableView]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_tableView)]];
/* Top and bottom constraints */
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_tableView]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_tableView)]];
...or if you really like to be explicit (and like typing):
/* Leading constaint (could use NSLayoutAttributeLeft here as well) */
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:0]];
/* Trailing constraint (could use NSLayoutAttributeRight here as well) */
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1 constant:0]];
/* Top constraint */
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
/* Bottom constraint */
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];
The important thing with all of this is that the UITableView is a child of the view of the UIViewController (it most likely is). view will fill the screen as expected by default, and with all of the methods above, you're asking the layout to hold tight against the edges of that maximized view.
NSLayoutConstraints is ridiculous overkill for this IMHO.
Just turn it off and do this
self.tableview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;