This is my first post to Stack Overflow, and I'm a iOS beginner, so please bear with me!
I have an example app where I have three UIViews (headerView, scrollViewContainer, and bodyView) in a parent UIView (topView), and all of these views are created in code. The topView is added to a UIScrollView (pageScrollView) created in storyboard.
pageScrollView is filling the full screen of an iPhone, and I used Autolayout. The app only contains the ViewController.h and companioning .m-file seen below, plus Appdelegate.x. I think I used the single view application template to start with. I'm using iOS 6 and Xcode 4.6, but I also tried 4.5.
I've tried to remove as much as possible of other code that's irrelevant to this problem.
The problem:
When the app starts it shows all its views correctly, and the scrollView allows to view all three views as intended. But after rotating to landscape, the scrollView somehow offsets the content. For example: Stay at top and rotate = content looks OK, but scroll down a bit and rotate makes the top of the content not to show.
What I have tried: I've searched the net for help, but I haven't found anything that seemed to help me. I've added logging of various data like origin, and contentSize, and also tried to set some of them but without any success. I also used 'po [[UIWindow keyWindow] _autolayoutTrace]' to ensure that the constraints are OK.
I can't see what I'm doing wrong. Are there any obvious things missing in my code?
Thanks in advance!
Here's the ViewController.m:
#import "ViewController.h"
#interface ViewController ()
{
UIView *topView;
UIView *headerView;
UIView *bodyView;
UIView *scrollViewContainer;
UIInterfaceOrientation newOrientation;
CGFloat bodyViewHeight;
CGSize newBounds;
float pictureScrollHeight;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
newBounds = [self sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation];
newOrientation = [UIApplication sharedApplication].statusBarOrientation;
bodyViewHeight = 1200; // The height of the body view varies in size depending on orientation
self.pageScrollView.translatesAutoresizingMaskIntoConstraints = NO;
topView = [[UIView alloc] init];
[topView setBackgroundColor:[UIColor clearColor]];
topView.translatesAutoresizingMaskIntoConstraints = NO;
[self.pageScrollView addSubview:topView];
headerView = [[UIView alloc] init];
[headerView setBackgroundColor:[UIColor redColor]];
headerView.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:headerView];
scrollViewContainer = [[UIView alloc] init];
[scrollViewContainer setBackgroundColor:[UIColor blueColor]];
scrollViewContainer.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:scrollViewContainer];
bodyView = [[UIView alloc] init];
[bodyView setBackgroundColor:[UIColor greenColor]];
bodyView.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:bodyView];
[self updateViewConstraints];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)updateViewConstraints
{
[super updateViewConstraints];
// Remove old constraints
[self.view removeConstraints:self.view.constraints];
[self.pageScrollView removeConstraints:self.pageScrollView.constraints];
[topView removeConstraints:topView.constraints];
[scrollViewContainer removeConstraints:scrollViewContainer.constraints];
if ((newOrientation == UIDeviceOrientationLandscapeLeft) || (newOrientation == UIDeviceOrientationLandscapeRight)) {
pictureScrollHeight = 300;
} else {
pictureScrollHeight = 203;
}
[headerView setNeedsDisplay];
[bodyView setNeedsDisplay];
CGFloat topViewHeight = bodyViewHeight + 55 + pictureScrollHeight;
//self.pageScrollView = _pageScrollView
NSDictionary *viewsDict = NSDictionaryOfVariableBindings(_pageScrollView, topView, headerView, bodyView, scrollViewContainer);
NSDictionary *metricsDict = #{#"topViewHeight": [NSNumber numberWithFloat:topViewHeight],
#"newBoundsWidth": [NSNumber numberWithFloat:newBounds.width],
#"pictureScrollHeight": [NSNumber numberWithFloat:pictureScrollHeight],
#"bodyViewHeight": [NSNumber numberWithFloat:bodyViewHeight]};
// pageScrollView - child to self.view
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[_pageScrollView]-0-|" options:0 metrics:nil views:viewsDict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[_pageScrollView]-0-|" options:0 metrics:nil views:viewsDict]];
// topView - child to pageScrollView
[self.pageScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[topView(newBoundsWidth)]-0-|" options:0 metrics:metricsDict views:viewsDict]];
[self.pageScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[topView(topViewHeight)]-0-|" options:0 metrics:metricsDict views:viewsDict]];
// headerView - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[headerView]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[headerView(55.0)]" options:0 metrics:nil views:viewsDict]];
// scrollViewContainer - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[scrollViewContainer]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-0-[scrollViewContainer(pictureScrollHeight)]" options:0 metrics:metricsDict views:viewsDict]];
// bodyView - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[bodyView]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[scrollViewContainer]-0-[bodyView(bodyViewHeight)]-0-|" options:0 metrics:metricsDict views:viewsDict]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
newOrientation = toInterfaceOrientation;
newBounds = [self sizeInOrientation:toInterfaceOrientation];
}
-(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation
{
CGSize size = [UIScreen mainScreen].bounds.size;
UIApplication *application = [UIApplication sharedApplication];
if (UIInterfaceOrientationIsLandscape(orientation))
{
size = CGSizeMake(size.height, size.width);
}
if (application.statusBarHidden == NO)
{
size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height);
}
return size;
}
#end
First of all you do not need to recreate all constraints in -updateViewConstraints method. You need to just update them in this place.
To achieve your aim do the following:
Create your constraints only once. For example in method -setupConstraints. And keep reference to those that need to be updated. See code below.
In method -updateViewConstraints just update topView height and width constraints and height for scrollViewContainer.
Here's the ViewController.m should look like:
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) IBOutlet UIScrollView* pageScrollView;
#property (nonatomic, strong) NSLayoutConstraint* pictureHeightConstraint;
#property (nonatomic, strong) NSLayoutConstraint* topViewWidthConstraint;
#property (nonatomic, strong) NSLayoutConstraint* topViewHeightConstraint;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
newBounds = [self sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation];
newOrientation = [UIApplication sharedApplication].statusBarOrientation;
bodyViewHeight = 1200; // The height of the body view varies in size depending on orientation
self.pageScrollView.translatesAutoresizingMaskIntoConstraints = NO;
topView = [[UIView alloc] init];
[topView setBackgroundColor:[UIColor clearColor]];
topView.translatesAutoresizingMaskIntoConstraints = NO;
[self.pageScrollView addSubview:topView];
headerView = [[UIView alloc] init];
[headerView setBackgroundColor:[UIColor redColor]];
headerView.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:headerView];
scrollViewContainer = [[UIView alloc] init];
[scrollViewContainer setBackgroundColor:[UIColor blueColor]];
scrollViewContainer.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:scrollViewContainer];
bodyView = [[UIView alloc] init];
[bodyView setBackgroundColor:[UIColor greenColor]];
bodyView.translatesAutoresizingMaskIntoConstraints = NO;
[topView addSubview:bodyView];
[self setupConstraints];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)setupConstraints {
// Remove old constraints
[self.view removeConstraints:self.view.constraints];
[self.pageScrollView removeConstraints:self.pageScrollView.constraints];
[topView removeConstraints:topView.constraints];
[scrollViewContainer removeConstraints:scrollViewContainer.constraints];
if ((newOrientation == UIDeviceOrientationLandscapeLeft) || (newOrientation == UIDeviceOrientationLandscapeRight)) {
pictureScrollHeight = 300;
} else {
pictureScrollHeight = 203;
}
[headerView setNeedsDisplay];
[bodyView setNeedsDisplay];
CGFloat topViewHeight = bodyViewHeight + 55 + pictureScrollHeight;
//self.pageScrollView = _pageScrollView
NSDictionary *viewsDict = NSDictionaryOfVariableBindings(_pageScrollView, topView, headerView, bodyView, scrollViewContainer);
// pageScrollView - child to self.view
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[_pageScrollView]-0-|" options:0 metrics:nil views:viewsDict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0- [_pageScrollView]-0-|" options:0 metrics:nil views:viewsDict]];
// topView - child to pageScrollView
[self.pageScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[topView]-0-|" options:0 metrics:nil views:viewsDict]];
[self.pageScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[topView]-0-|" options:0 metrics:nil views:viewsDict]];
NSLayoutConstraint* topViewWidthConstraint = [NSLayoutConstraint constraintWithItem:topView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:newBounds.width];
self.topViewWidthConstraint = topViewWidthConstraint;
[topView addConstraint:self.topViewWidthConstraint];
NSLayoutConstraint* topViewHeightConstraint = [NSLayoutConstraint constraintWithItem:topView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:topViewHeight];
self.topViewHeightConstraint = topViewHeightConstraint;
[topView addConstraint:self.topViewHeightConstraint];
// headerView - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[headerView]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[headerView(55.0)]" options:0 metrics:nil views:viewsDict]];
// scrollViewContainer - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[scrollViewContainer]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-0-[scrollViewContainer]" options:0 metrics:nil views:viewsDict]];
NSLayoutConstraint* pictureHeightConstraint = [NSLayoutConstraint constraintWithItem:scrollViewContainer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:pictureScrollHeight];
self.pictureHeightConstraint = pictureHeightConstraint;
[scrollViewContainer addConstraint:self.pictureHeightConstraint];
// bodyView - child to topView
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[bodyView]-0-|" options:0 metrics:nil views:viewsDict]];
[topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V: [scrollViewContainer]-0-[bodyView]-0-|" options:0 metrics:nil views:viewsDict]];
}
- (void)updateViewConstraints
{
[super updateViewConstraints];
if ((newOrientation == UIDeviceOrientationLandscapeLeft) || (newOrientation == UIDeviceOrientationLandscapeRight)) {
pictureScrollHeight = 300;
} else {
pictureScrollHeight = 203;
}
CGFloat topViewHeight = bodyViewHeight + 55 + pictureScrollHeight;
self.pictureHeightConstraint.constant = pictureScrollHeight;
self.topViewHeightConstraint.constant = topViewHeight;
self.topViewWidthConstraint.constant = newBounds.width;
[self.pageScrollView setNeedsUpdateConstraints];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
newBounds = [self sizeInOrientation:toInterfaceOrientation];
}
-(CGSize)sizeInOrientation:(UIInterfaceOrientation)orientation
{
CGSize size = [UIScreen mainScreen].bounds.size;
UIApplication *application = [UIApplication sharedApplication];
if (UIInterfaceOrientationIsLandscape(orientation))
{
size = CGSizeMake(size.height, size.width);
}
if (application.statusBarHidden == NO)
{
size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height);
}
return size;
}
#end
ScrollView calculates its content size automatically depending on subviews constraints added into it. Off course it works only in autolayout enviroument.
Check the auto-resizing masks.
[self.pageScrollView setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
It looks like that you are NOT doing anything with the newBounds in willRotateToInterfaceOrientation. Shouldn't you call your updateView method after getting the new bounds.
Related
I want to display a whole chapter of a book with UILabel in a scrollview. But seems the content is too large to display, and gives following error:
[2835:157182] -[<_UILabelContentLayer: 0x60400023b040> display]: Ignoring bogus layer size (378.666667, 883959.333333), contentsScale 3.000000, backing store size (1136.000000, 2651878.000000)
And I searched for answers and some guys suggest I should use a CATiledLayer to solve this, but they didn't give a clear clue of how to do this, anyone could give some help?
Thanks,
- (void)viewDidLoad {
[super viewDidLoad];
/*** Init the scrollview and the label ***/
UIScrollView *scrollView= [UIScrollView new];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollView];
UILabel *scrollViewLabel = [[UILabel alloc] init];
scrollViewLabel.numberOfLines = 0;
scrollViewLabel.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:scrollViewLabel];
scrollViewLabel.text = #"";
NSArray *array = [Utils getCharptersWithName:#"mybook"];
for(NSDictionary *dic in array){
scrollViewLabel.text = [scrollViewLabel.text stringByAppendingString:[dic objectForKey:#"content"]];
}
NSLog(#"%#", scrollViewLabel.text);
/*** Auto Layout ***/
NSDictionary *views = NSDictionaryOfVariableBindings(scrollView, scrollViewLabel);
NSArray *scrollViewLabelConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollViewLabel(scrollView)]" options:0 metrics:nil views:views];
[scrollView addConstraints:scrollViewLabelConstraints];
scrollViewLabelConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollViewLabel]|" options:0 metrics:nil views:views];
[scrollView addConstraints:scrollViewLabelConstraints];
NSArray *scrollViewConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[scrollView]-|" options:0 metrics:nil views:views];
[self.view addConstraints:scrollViewConstraints];
scrollViewConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[scrollView]-|" options:0 metrics:nil views:views];
[self.view addConstraints:scrollViewConstraints];
// Do any additional setup after loading the view.
}
I'm trying to make a theos tweak that will blur the background and show a text field of password when user enters any application. The text field that I use is a custom text field class(JVFloatLabeledTextField). The code works just fine without the custom text field but when I add it, the springboard crashes.
Here is the code:
#import "JVFloatLabeledTextField.h"
typedef enum {
SBIconLocationHomeScreen = 0,
SBIconLocationDock = 1,
SBIconLocationSwithcer = 2
} SBIconLocation;
#interface SBApplicationIcon
- (void)launchFromLocation:(SBIconLocation)location context:(id)arg2;
#end
%hook SBApplicationIcon
- (void)launchFromLocation:(SBIconLocation)location context:(id)arg2 {
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
[blurEffectView setFrame:window.bounds];
[UIView transitionWithView:window duration:0.4 options:UIViewAnimationOptionTransitionCrossDissolve animations: ^ {
[window addSubview:blurEffectView];
} completion:nil];
blurEffectView.translatesAutoresizingMaskIntoConstraints = NO;
[window addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[blurEffectView]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:NSDictionaryOfVariableBindings(blurEffectView)]];
[window addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[blurEffectView]|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(blurEffectView)]];
JVFloatLabeledTextField *pwt = [[%c(JVFloatLabeledTextField) alloc] initWithFrame:CGRectMake(0, 0, 120, 44)];
pwt.font = [UIFont systemFontOfSize:16.0f];
pwt.attributedPlaceholder = [[NSAttributedString alloc] initWithString:NSLocalizedString(#"Enter your password", #"")
attributes:#{NSForegroundColorAttributeName: [UIColor lightGrayColor]}];
pwt.textColor = [UIColor whiteColor];
pwt.floatingLabelFont = [UIFont boldSystemFontOfSize:11.0f];
pwt.floatingLabelTextColor = [UIColor greenColor];
pwt.tintColor = [UIColor greenColor];
pwt.keyboardType = UIKeyboardTypeNumberPad;
pwt.translatesAutoresizingMaskIntoConstraints = NO;
pwt.clearButtonMode = UITextFieldViewModeWhileEditing;
[UIView transitionWithView:window duration:0.4 options:UIViewAnimationOptionTransitionCrossDissolve animations: ^ {
[window addSubview:pwt];
} completion:nil];
[window addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|-210-[pwt(>=44)]"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(pwt)]];
[window addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"H:[pwt]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(pwt)]];
[window addConstraint:[NSLayoutConstraint
constraintWithItem:pwt attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:window attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
}
%end
Can you tell me what is the problem in the code?
Thanks in advance.
I need a view controller without xib. There should be a webview with fully filled to the view. For that I've added the following code to loadView method.
- (void)loadView {
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
UIView *view = [[UIView alloc] initWithFrame:applicationFrame];
view.translatesAutoresizingMaskIntoConstraints = NO;
[view setBackgroundColor:[UIColor greenColor]];
[self setView:view];
// //create webview
self.webview = [[UIWebView alloc] initWithFrame:CGRectZero];
self.webview.translatesAutoresizingMaskIntoConstraints = NO;
[view addSubview:self.webview];
[self.webview setBackgroundColor:[UIColor orangeColor]];
[self.webview setDelegate:self];
NSDictionary *viewBindings = NSDictionaryOfVariableBindings(view,_webview);
// //add constraints
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_webview]|" options:0 metrics:nil views:viewBindings]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_webview]|" options:0 metrics:nil views:viewBindings]];
}
But this turns the entire view to black. If I coment [view addConstraints:... method calls its showing a green view. What's wrong with my code?
I believe that the problem is that the parent view should not set translatesAutoresizingMaskIntoConstraints to false. The only view that must set that attribute to false is the one you are applying autolayout to, in this case webView. If you set view.translatesAutoresizingMaskIntoConstraints to false then you have to add constraints to view.
You don't need to change the root view of the UIViewController manually, maybe that's why it does not work.
My suggestion would be to try this out:
- (void) viewDidLoad {
[super viewDidLoad];
self.webview = [[UIWebView alloc] init];
self.webview.translatesAutoresizingMaskIntoConstraints = NO;
[view addSubview:self.webview];
[self.webview setBackgroundColor:[UIColor orangeColor]];
[self.webview setDelegate:self];
NSDictionary *viewBindings = NSDictionaryOfVariableBindings(view,_webview);
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[_webview]-0-|" options:0 metrics:nil views:viewBindings]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[_webview]-0-|" options:0 metrics:nil views:viewBindings]];
// put a breakpoint after this line to see the frame of your UIWebView.
// It should be the same as the view
[self.view layoutIfNeeded];
}
This should work and your UIWebView should be full screen. Good luck!
I'm attaching a UIImageView and UILabel to a UIScrollView. I'm shrinking the image to half it's height, and when I do that, the label ends up right in the middle of the image vertically rather than right below it. If I don't force the image smaller, the label sits right below the image as expected.
How do I shrink an image and still have my label sit right below it?
UIScrollView *scrollView;
UIImageView *myImage;
NSDictionary *viewsDictionary;
UILabel *myLabel;
scrollView = [[UIScrollView alloc] init];
myImage = [[UIImageView alloc] init];
myLabel = [[UILabel alloc] init];
[myImage setImage:[UIImage imageNamed:#"vacation-house-004.jpg"]];
[myImage setContentMode: UIViewContentModeScaleAspectFill];
[myLabel setText: #"test label"];
[self.view addSubview:scrollView];
[scrollView addSubview:myImage];
[scrollView addSubview:myLabel];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
myImage.translatesAutoresizingMaskIntoConstraints = NO;
myLabel.translatesAutoresizingMaskIntoConstraints = NO;
// Set the constraints for the scroll view and the image view.
viewsDictionary = NSDictionaryOfVariableBindings(scrollView, myImage, myLabel);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[myImage(==scrollView)]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[myImage(50)]-[myLabel]|" options:0 metrics: 0 views:viewsDictionary]];
Thank you!
Figured it out, had to add: myImage.clipsToBounds = YES;
UIView *superView = self.view;
UIScrollView *scrollView;
UIImageView *myImage;
NSDictionary *viewsDictionary;
UILabel *myLabel;
scrollView = [[UIScrollView alloc] init];
myImage = [[UIImageView alloc] init];
myLabel = [[UILabel alloc] init];
myImage.image = [UIImage imageNamed:#"vacation-house-004.jpg"];
myImage.contentMode = UIViewContentModeScaleAspectFill;
myImage.clipsToBounds = YES;
myLabel.text = #"test label";
myLabel.backgroundColor = [UIColor blackColor];
[superView addSubview:scrollView];
[scrollView addSubview:myImage];
[scrollView addSubview:myLabel];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
myImage.translatesAutoresizingMaskIntoConstraints = NO;
myLabel.translatesAutoresizingMaskIntoConstraints = NO;
// Set the constraints for the scroll view and the image view.
viewsDictionary = NSDictionaryOfVariableBindings(superView, scrollView, myImage, myLabel);
[superView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[superView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[myImage(==scrollView)]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[myImage(150)]-[myLabel]|" options:0 metrics: 0 views:viewsDictionary]];
I'm animating a custom view off screen using a constraint on view's top edge.
The view is:
#implementation MyView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor yellowColor]];
_label = [UILabel new];
[_label setTranslatesAutoresizingMaskIntoConstraints:NO];
_label.text = #"text";
[self addSubview:_label];
[self updateConstraints];
}
return self;
}
- (void)updateConstraints
{
NSDictionary *views = NSDictionaryOfVariableBindings(_label);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[_label]"
options:NSLayoutFormatAlignAllLeft
metrics:nil
views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[_label]"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:views]];
[super updateConstraints];
}
#end
The constraint for animating myView on its parent view is:
_myViewTopConstraint = [NSLayoutConstraint constraintWithItem:_myView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-kMyViewVisibleHeight];
[self.view addConstraint:_myViewTopConstraint];
The animation on the top edge constraint is:
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.myViewTopConstraint.constant = kScreenHeight;
[self.myView layoutIfNeeded];
} completion:nil];
When the label and constraints in MyView is commented out, the animation works perfectly. But when the label and constraints are there, the animation is sped up significantly, maybe 5x or more.
Why does this happen? Anyone know how to fix it?
Figured it out. layoutIfNeeded must be called on myView's parent view in the animation block.
[self.myView layoutIfNeeded];
changed to
[self.view layoutIfNeeded];