AutoLayout container relative position not recognised under ios8 beta 4 - objective-c

In my view, I init a view like this:
UIView *statsView = [[UIView alloc] initWithFrame:CGRectMake(10, 130, 200, 12)];
Inside this view, I create 3 autolayout subviews contained in this previous view.
for (UIButton* v in [statsView subviews]) {
v.translatesAutoresizingMaskIntoConstraints = NO;
[statsView addSubview:v];
}
NSDictionary *views = #{#"reposts": v1,
#"likes": v2,
#"comments": v3
};
[statsView addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"H:|[reposts][likes][comments]"
options:NSLayoutFormatAlignAllTop| NSLayoutFormatAlignAllBottom
metrics:0
views:views]];
On IOS7 , the Y position of the container is 130 (defined in the initWithFrame), but with ios8, the Y position looks like "0".
Any ideas?

I ask an other question about the same problem and Saldorino give me a good answer
Xcode6 - Autolayout view in an other autolayout view
The issue lies in the missing the vertical position constraint.
[statsView addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|[comments]"
options:0
metrics:0
views:views]];

Related

Centring images to a view using autolayout Objective C

I have two images - profileImageView, profileImageViewOfLoggedInUser which is 20px apart from each other and i want to centre them to the view.
Below is my source code
static CGFloat const MeetingDetailNameLabelMarginX = 20;
NSDictionary *views = #{
#"imageView": self.profileImageView,
#"imageViewForLoggedInUser": self.profileImageViewOfLoggedInUser,
#"nameLabel": self.nameLabel,
#"companyNameLabel": self.companyNameLabel,
#"positionLabel": self.positionLabel,
#"statusLabel": self.statusLabel,
};
NSDictionary *metrics = #{
#"imagePaddingLeft": #(MeetingDetailImageViewMarginX),
#"imagePaddingTop": #(MeetingDetailImageViewMarginY),
#"nameLabelPaddingLeft": #(MeetingDetailNameLabelMarginX),
#"nameLabelPaddingRight": #(MeetingDetailNameLabelMarginRightX),
#"nameLabelPaddingTop": #(MeetingDetailImageViewSize + MeetingDetailImageViewMarginY),
#"imageSize": #(MeetingDetailImageViewSize),
#"nameLabelHeight": #(nameLabelFrame.size.height),
#"otherLabelHeight": #(MeetingDetailOtherLabelHeight),
#"dateLabelWidth": #(self.dateLabel.frame.size.width),
#"statusLabelWidth": #(statusFrame.size.width),
#"statusLabelMarginLeftFromView": #(MeetingDetailImageViewMarginX),
};
// image left and width
[self.detailContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"[imageView(imageSize)]"
options:0
metrics:metrics
views:views]];
[self.detailContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-imagePaddingLeft-[imageViewForLoggedInUser(imageSize)]"
options:0
metrics:metrics
views:views]];
// image top and height
[self.detailContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-imagePaddingTop-[imageView(imageSize)]"
options:0
metrics:metrics
views:views]];
[self.detailContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-imagePaddingTop-[imageViewForLoggedInUser(imageSize)]"
options:0
metrics:metrics
views:views]];
Please let me know the code to be added.
I get the UI as seen in below screenshot on adding the following code:-
NSLayoutConstraint *centerXConstraint = [self.detailContainer.centerXAnchor constraintEqualToAnchor:_profileImageView.centerXAnchor];
[self.detailContainer addConstraint:centerXConstraint];
If you want to center ImageView relative it's superview, you shouldn't specify some strange margins or something else. All you have to do is specify 2 constraints for centering and 2 constraints for size of imageView.
From iOS 9 you can use these simple api:
NSLayoutConstraint *centerXConstraint = [superView.centerXAnchor constraintEqualToAnchor:imageView.centerXAnchor];
NSLayoutConstraint *centerYConstraint = [superView.centerYAnchor constraintEqualToAnchor:imageView.centerYAnchor];
NSLayoutConstraint *imageViewHeight = [imageView.heightAnchor constraintEqualToConstant:heightValue];
NSLayoutConstraint *imageViewWidth = [imageView.widthAnchor constraintEqualToConstant:widthValue];
Then, you are able to constrain second image view relative to first image view (since first one is already constrained). You can use VFL for it, or whatever.

Set PKPaymentButton width to superview?

I'm adding a PKPaymentButton programmatically (because it doesn't seem like I can simply set a UIButton to PKPaymentButton in storyboard). I'd like my PKPaymentButton to be width of its superview. However, this does not seem to be working. (The PKPaymentButton maintains a predefined width of 140pts.) I've tried setting the horizontal contentHuggingPriority of my PKPaymentButton to UILayoutPriorityDefaultLow but that seems to have no effect. Any ideas how to get a full-width PKPaymentButton that adjusts to the width of my screen?
I've created container view in storyboard, and then added to it PKPaymentButton with necessary constraints.
Here is simple method from my UIView category that makes it easy:
-(void) setupWithContentView:(UIView *) contentView
{
contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:contentView];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[contentView]|"
options:0
metrics:nil
views:#{#"contentView":contentView}]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[contentView]|"
options:0
metrics:nil
views:#{#"contentView":contentView}]];
}

How to add QLPreviewController as Subview in objective C - iOS8

In previous iOS versions I used to add the QLPreviewController as a subview. It is very handy to use my own app headers and navigation bar but in iOS 8 it adds a white space just below the header. It is the space for its own navigator bar.
You can see the attached img:
I use this code:
QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
previewController.currentPreviewItemIndex = 0;
previewController.view.frame = CGRectMake(0, 0, self.containerView.frame.size.width, self.containerView.frame.size.height);
[self addChildViewController:previewController];
[previewController didMoveToParentViewController:self];
[self.containerView addSubview:previewController.view];
How can i mantain the iOS7 funcionality? I only want to hide the qlpreviewcontroller navigationbar
Thanks
I'm solving the EXACT same problem. The only solution I found so far is the following:
// qlController.view.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));//self.view.bounds;
// qlController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addChildViewController:qlController];
[self.view addSubview:qlController.view];
NSDictionary *bindings = #{#"qlPreviewController": qlController.view};
qlController.view.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[qlPreviewController]|" options:0 metrics:nil views:bindings]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[qlPreviewController]|" options:0 metrics:nil views:bindings]];
[qlController didMoveToParentViewController:self];
Commented lines are legacy code, that worked perfectly on iOs7. The main idea is stop using spring and struts and start using auto layout. Results looks good enough, but still there are some problems with rotations.
Works good:
Iphone 4s/5/6/6+ iOs7 portrait + landscape, iOs8 portrait
IPad all models iOs7,8 portrait + landscape
Works bad:
Iphone 4s/5/6/6+ iOs8 landscape : has some spacing between navBar and content. I think it is problem with Apple's QLPreviewController rather than my code.

UIStoryboard how to replace constraints programmatically?

I have a view controller laid out in a storyboard with autolayout enabled and am looking for a way to change constraints to allow for my view to rotate into landscape and rearrange buttons on the screen. When I try the code below, I get about two dozen "unable to satisfy constraints, breaking constraint..." messages that I cannot really decode.
Is there a way to dynamically replace constraints from a storyboard with constraints that I specify programmatically? I want to completely override the layout of the buttons that I defined in a storyboard.
-(void)updateViewConstraints
{
[super updateViewConstraints];
self.loginButton.translatesAutoresizingMaskIntoConstraints = NO;
self.getStartedButton.translatesAutoresizingMaskIntoConstraints = NO;
self.takeTourButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.loginButton removeConstraints:self.loginButton.constraints];
[self.getStartedButton removeConstraints:self.getStartedButton.constraints];
[self.takeTourButton removeConstraints:self.takeTourButton.constraints];
one = self.loginButton;
two = self.getStartedButton;
three = self.takeTourButton;
NSDictionary *metrics = #{#"height":#50.0,#"width":#100.0,#"leftSpacing":#110.0};
NSDictionary *views = NSDictionaryOfVariableBindings(one,two,three);
[self.view removeConstraints:activeTestLabelConstraints];
[activeTestLabelConstraints removeAllObjects];
if(isRotatingToLandscape)
{
[self registerConstraintsWithVisualFormat:#"|-[one(two)]-[two(three)]-[three]-|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:metrics views:views];
[self registerConstraintsWithVisualFormat:#"V:[one(height)]-|" options:0 metrics:metrics views:views];
}else
{
[self registerConstraintsWithVisualFormat:#"|-leftSpacing-[one(width)]" options:0 metrics:metrics views:views];
[self registerConstraintsWithVisualFormat:#"[two(width)]" options:0 metrics:metrics views:views];
[self registerConstraintsWithVisualFormat:#"[three(width)]" options:0 metrics:metrics views:views];
[self registerConstraintsWithVisualFormat:#"V:[one(height)]-[two(75)]-[three(100)]-|" options:NSLayoutFormatAlignAllCenterX metrics:metrics views:views];
}
}
Updated with Rob's answer, here's the method to remove constraints that I use
-(void)removeConstraintForView:(UIView*)viewToModify
{
UIView* temp = viewToModify;
[temp removeFromSuperview];
[self.view addSubview:temp];
}
It sounds like you want to just remove all the constraints on a view. Since constraints on a view are often held by an ancestor of the view, it's not obvious how to remove all of the constraints easily. But it is actually pretty easy.
Removing a view from the view hierarchy removes any constraints betwixt the view and other views outside of it. So just remove your view from its superview and then add it back:
// Remove constraints betwixt someView and non-descendants of someView.
UIView *superview = someView.superview;
[someView removeFromSuperview];
[superview addSubview:someView];
If there are any constraints betwixt someView and its descendants, those constraints might be held by someView itself (but cannot be held by any descendants of someView). If you want to remove those constraints also, you can do so directly:
// Remove any remaining constraints betwixt someView and its descendants.
[someView removeConstraints:[someView constraints]];

Subview remove and add in objective c/iphone

I have a UIViewController class where I create a UIView instance.
And then I initialize (means fill) it with 25 subviews each containing an image (1, 2, ..., 25). Then after clicking 5 times in these image I called a function where I used
for(UIView *subview in [contentView subviews]) {
[subview removeFromSuperview];//ContentView name of my view
}
to remove the previously added subview. And then I use the same approch to
add 25 new subviews (image 1,2,3,....25). But this time no subview is added.
Can someone plz give me full code of adding & removing subview.
I have used the following code when I first add subview
//create main window
contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
contentView.backgroundColor = [UIColor blackColor];
self.view = contentView;
[contentView release];
//adding 25 subview 1st time
int a=0;
int b=0;
for (int i = 0; i < 26; i++)
{
CGRect dragRect = CGRectMake(0.0f, 0.0f, x, y);
dragRect.origin = CGPointMake(a,b);
DragView *dragger = [[DragView alloc] initWithFrame:dragRect];
NSString *Flower = [[NSArray arrayWithObjects:#"1.png", #"2.png", #"3.png",#"4.png", #"5.png", #"6.png",#"7.png",#"8.png", #"9.png",#"10.png", #"11.png", #"12.png",#"13.png",#"14.png",#"15.png",#"16.png",#"17.png",#"18.png",#"19.png",#"20.png",#"21.png",#"22.png",#"23.png",#"24.png",#"25.png",#"26.png", nil] objectAtIndex:i];
[dragger setImage:[UIImage imageNamed:Flower]];
[dragger setUserInteractionEnabled:YES];
[self.view addSubview:dragger];
[dragger release];
a+=10;
b+=10;
}
//then removing 25 subview
//adding 25 subview 2nd times
I used the same approch to add the second time as first time, but the problem is that when I remove 25 subview and then add 25 subview, these subview are not added/shown, the view remain same. I am tired with these problem. plz someone help me.
The problem might be the way you remove the old views. You are modifying an array while iterating over it, which does not work. Try this code to remove the old views:
UIView* subview;
while ((subview = [[contentView subviews] lastObject]) != nil)
[subview removeFromSuperview];
A nice one liner is:
[view.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
Looking at your code, I can suggest the following changes. There's one line in your for loop which is terribly inefficient:
NSString *Flower = [[NSArray arrayWithObjects:#"1.png", #"2.png", #"3.png",#"4.png", #"5.png", #"6.png",#"7.png",#"8.png", #"9.png",#"10.png", #"11.png", #"12.png",#"13.png",#"14.png",#"15.png",#"16.png",#"17.png",#"18.png",#"19.png",#"20.png",#"21.png",#"22.png",#"23.png",#"24.png",#"25.png",#"26.png", nil] objectAtIndex:i];
[dragger setImage:[UIImage imageNamed:Flower]];
Either take the Flower initialisation out of the the for loop (to only create the array once) or do the following:
[dragger setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%d.png", i]]];
The code itself looks like it should work though. If you add 26 subviews then remove the 26 subviews then add the 26 subviews in exactly the same way then it should display as you'd expect.