Programmatically using constraints to center a UIIMageView - ios

I'm working on an iOS project in which I need to programmatically use constraints for my views. I'm used to storyboards, but am using xibs for this particular project due to the nature of the project specification.
I have a MainViewController, in which I create the following properties in the .h file:
#property (nonatomic, strong) IBOutlet UIImageView *backgroundImageView;
#property (nonatomic, strong) IBOutlet UIImageView *logoImage;
I added these UIImageView instances to my XIB file, and selected the appropriate images via the Attributes inspector.
In my .m file, I have a addConstraints method, which is called in viewDidLoad. Inside this method, I make sure to turn off converting autoresizingMasks into constraints:
self.backgroundImageView.translatesAutoresizingMaskIntoConstraints = NO;
self.logoImage.translatesAutoresizingMaskIntoConstraints = NO;
Then, I've set up constraints so that the background image takes up the entirety of the superview:
id mainView = #{#"background": self.backgroundImageView};
//Set constraints so that the background takes up the entirety of the superview
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[background]|" options:0 metrics:nil views:mainView]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[background]|" options:0 metrics:nil views:mainView]];
Finally, I set constraints so that the logo view is in the center of the view (which is where I am going wrong):
// Width constraint
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoImage
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:0]];
// Height constraint
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoImage
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeHeight
multiplier:0.5
constant:0]];
// Center horizontally
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoImage
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
// Center vertically
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoImage
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
The error I receive is
*** +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]:
Constraint items must each be an instance of UIView or subclass'
, which I don't fully understand, as my constraint items (two UIImageView instances) are either subclasses of UIView, but I may be misunderstanding this. Can anyone help point out where I'm going wrong?

Try that :
// Width constraint
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoImage
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.backgroundImageView
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:0]];
// Height constraint
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoImage
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.backgroundImageView
attribute:NSLayoutAttributeHeight
multiplier:0.5
constant:0]];
// Center horizontally
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoImage
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.backgroundImageView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
// Center vertically
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoImage
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.backgroundImageView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
You were trying to define constraints between your UIImageView and your view controller. You must define constraints between views which are subviews of a same view.

Related

Center view inside another view

I have a view called profile which is taking (0,0,320,60) size in storyboard which is taking full width but 60 height, and i am trying to place another view called ranking inside it at the center and what ever the device is iPhone4s,5s,6s,6 it should just take my view and put it at the center.
Here is what i tried:
ranking.frame = CGRectMake(0, 0, 120, 60);
ranking.center = self.Profile.center;
The current code is not centering my view In all devices. what can i do to do it dynamically ?
You can use AutoLayout with the following method:
+ (void)centerView:(UIView *)view inContainerView:(UIView *)containerView withSuperView:(UIView *)superView
{
[superView addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[superView addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
}
You can add the method above in your ViewController or in a helper class.
Remember to set the translatesAutoresizingMaskIntoConstraints property to false before using AutoLayout on your view.
So if ranking is your subview and self.Profile is your superView you can do the following.
UIView *ranking = [[UIView alloc] init];
ranking.translatesAutoresizingMaskIntoConstraints = false;
[self.Profile addSubview:ranking];
[[self class] centerView:ranking inContainerView:self.Profile withSuperView:self.Profile];
[self.Profile addConstraint:[NSLayoutConstraint constraintWithItem:ranking attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:120]];
[self.Profile addConstraint:[NSLayoutConstraint constraintWithItem:ranking attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:60]];

How to set equal widths for UIViews using auto-layouts "Constraint with item format"

In my application I have inserted UIViews on view controller. My main requirement is that I want to set equal widths for both UIViews using auto-layouts "Constraint with item format".
For this I have written some code but I did not get equal widths. What did I do here wrong?
I want get result like below image (i.e need to set equal widths for both UIViews).
My code:
#import "ViewController8.h"
#interface ViewController8 ()
{
UIView * myView1;
UIView * myView2;
}
#end
#implementation ViewController8
- (void)viewDidLoad {
[super viewDidLoad];
myView1 = [[UIView alloc] init];
myView1.backgroundColor = [UIColor lightGrayColor];
myView1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:myView1];
myView2 = [[UIView alloc] init];
myView2.backgroundColor = [UIColor redColor];
myView2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:myView2];
[self operation2];
}
-(void)operation2
{
//Applying autolayouts for myview2
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:50]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-10]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-30]];
//Applying autolayouts for myview1
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:10]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:50]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:myView2
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:-30]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-30]];
}
Equal width constraint is not there in your posted code. Try adding this
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:myView1
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0]];
It's enough to add the equal-width constraint
[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:myView2
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
You must not define the width of the two views explicitly using constraints because view1 is pinned to the leading edge of the superview, view2 is pinned to the trailing edge of the superview and the trailing edge of view1 is pinned to the leading edge of view2. Hence, the constraint system is fully determined after adding the above equal-width constraint.
This is what adding the constraint will lead to:
Contemporary solution is using NSLayoutAnchor
myView1.widthAnchor.constraint(equalTo: myView2.widthAnchor)
don't forget to activate this using isActive = true, or via NSLayoutConstraint.activate().

How to add layout for subview and subview button label step by step in ios?

How to add constraint for subview of view controller
explain briefly
// create a new view
self.containerView = [UIView new];
// before adding constraints always add respective view to superview
[self.view addSubview:self.containerView];
[self.containerView setTranslatesAutoresizingMaskIntoConstraints:false];
// add container on newly added view
NSLayoutConstraint *topConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
NSLayoutConstraint *leadingConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.containerView.superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
NSLayoutConstraint *trailingConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.containerView.superview attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
NSLayoutConstraint *bottomConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.bottomLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
// add constraint to superview of respective view
[self.view addConstraints:#[topConstraintContainer,leadingConstraintContainer,trailingConstraintContainer,bottomConstraintContainer]];
There are alot of possibilities, but this is the main flow
Also there are third party libraries available which makes adding constraints easier, like
PureLayout

Facebook Audience Network ios FBAdView width

I added a FBAdView to a UIView in the view controller.
(I set the view background to red)
the FBAdView was created with adSize of kFBAdSizeHeight50Banner.
The problem is that the FBAdView calculates its width when it is being added, but after rotating the device it doesn't calculate its width again
I tried using autolayout but it didn't work
code for adding the FBAdview (Adding to UILabel with red backgroud)
FBAdView *fbAdView = [[FBAdView alloc] initWithPlacementID:#"***************_***************"
adSize:kFBAdSizeHeight50Banner
rootViewController:self];
fbAdView.delegate = self;
[fbAdView loadAd];
[self.banner addSubview:fbAdView];
code for autolayout - doesn't work
// Width constraint, parent view width
[self.banner addConstraint:[NSLayoutConstraint constraintWithItem:fbAdView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.banner
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
// Height constraint, parent view height
[self.banner addConstraint:[NSLayoutConstraint constraintWithItem:fbAdView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.banner
attribute:NSLayoutAttributeHeight
multiplier:1
constant:0]];
// Center horizontally
[self.banner addConstraint:[NSLayoutConstraint constraintWithItem:fbAdView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.banner
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
// Center vertically
[self.banner addConstraint:[NSLayoutConstraint constraintWithItem:fbAdView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.banner
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
print screen
when the banner is added it fit the screen width
after rotating it doesn't change its width (like its parent red view)
I think you're missing some constraints.
Adding these lines (might need some minor changes) makes your code work:
self.banner.translatesAutoresizingMaskIntoConstraints = NO;
fbAdView.translatesAutoresizingMaskIntoConstraints = NO;
// Width constraint
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.banner
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
// Height constraint
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[banner(==50)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(banner)]];
I've posted a sample project at https://github.com/overlordnyaldee/BannerAutoLayout

UIScrollView has wrong contentSize with auto layout

I have a iOS screen in storyboard that look like that:
If I try this in simulator, I can't scroll to second UIView (I using paging). I know that this is happening because width of contentSize is 320, but I don't know ho to solve it using auto layout and I don't know how to make it work on every device position (landscape, portrait). I need to display only one UIView in UIScrollView. Thanks.
It is solvable and should work well with Auto Layout.
NSDictionary *views = NSDictionaryOfVariableBindings(scrollView, subview1, subview2);
// Constraint the scrollview frame within its parent
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
// Determine the scrollview's contentSize using its content
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[subview1]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[subview1][subview2]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[subview2]|" options:0 metrics: 0 views:viewsDictionary]];
// Set the children width using the outer view
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:subview1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:subview2 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
// Set the children height manually
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:subview1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:80.0]];
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:subview2 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:80.0]];
Tell me if you get issues. This approach will have the advantage of adapting to screen orientation, screen size, status bar height change, and so on.
The above example assumes you want to set the children's height to a fixed height (80 pixels). To make it fill the screen vertically, you would rather do the same as is done for width.
This also assumes scrollview, subview1 and subview2 all have their translatesAutoresizingMaskIntoConstraints property set to NO.
It will also not align the subviews vertically within the scrollview. If you wanted to do that, you could instead have each of them reside in their own container view like this :
// Set the containers' width & height using the outer view
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:containerview1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:containerview2 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:containerview1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0]];
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:containerview2 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:parentView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0]];
// Set the children height manually
[containerview1 addConstraint:[NSLayoutConstraint constraintWithItem:subview1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:80.0]];
[containerview2 addConstraint:[NSLayoutConstraint constraintWithItem:subview2 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:80.0]];
// Align them vertically
[containerview1 addConstraint:[NSLayoutConstraint constraintWithItem:subview1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:containerview1 attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[containerview2 addConstraint:[NSLayoutConstraint constraintWithItem:subview2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:containerview2 attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
// Set the width to equal that of their container
[containerview1 addConstraint:[NSLayoutConstraint constraintWithItem:subview1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:containerview1 attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
[containerview2 addConstraint:[NSLayoutConstraint constraintWithItem:subview2 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:containerview2 attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
Just try something like this:
[_scrollView setContentSize:CGSizeMake(640, _scrollView.frame.size.height)];
Regarding to autolayouts: sometimes it's better to get a rid of using them.
The code which considers screen orientation:
float screenWidth = [UIScreen mainScreen].bounds.size.width;
[_scrollView setContentSize:CGSizeMake(screenWidth * 2, _scrollView.frame.size.height)];
To catch the moment when device get rotated you should use such method within your view controller:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
// Remove current subviews
for(UIView *subview in _scrollView.subviews)
{
[subview removeFromSuperview];
}
// Fill scroll view with subviews resized for screen size
// ...
}

Resources