I am using constraints to lay out a view controller in my app. Here is a screenshot of the completed layout:
From what I've read, the constraints being blue means they are good (there is enough information to determine layout).
In another view controller, I am presenting this view controller with a popover presentation style like this:
- (void)annotationTapped:sender {
...
AJFAnswerViewController *answerViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"AnswerViewController"];
answerViewController.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:answerViewController animated:YES completion:nil];
answerViewController.answerLabel.text = tappedAnnotation.name;
answerViewController.quesitonLabel.text = tappedAnnotation.questionText;
answerViewController.saveBlock = saveBlock;
UIPopoverPresentationController *popover = [answerViewController popoverPresentationController];
popover.sourceView = tap.view;
popover.sourceRect = tap.view.bounds;
popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
}
Here is what I see when I run the app:
It seems that the constraints are not being applied. I have verified that my storyboard ID is correct, and that the popover is using the view controller in the popover (for example, if I change the explicit height to something like 100, it is respected).
Am I missing a specific method call, or going about the storyboard layout wrong?
Resolved by applying the constraints to the wAny hAny size (as suggested by Dean, thanks!).
select all the labels and make them embed in a new view (Xcode-editor-embed-view)
select the view which the labels embeded in and add a new alignment constraint (horizontal center in container : 0; vertical center in container : 0)
rebuild those label constraint
Related
I wanted to post a gif but apparently I don't have enough reputation. Oh well, whatever; I was using UIPageViewController, but for some reason I decided to go with a more manual solution by using UIScrollView and adding the views of UITableViewControlllers to the corresponding offsets (pages). I have 4 UItableViewControllers on each page (the views of table view controllers) and all of these are added to the container view controller (which has the UIScrollView) as child view controllers.
The actual problem is when I made the switch, table views began refusing to go all the way down and part of the final table view cell stays trimmed by the end of the screen when the scrolling ends.
So, wanted to ask if anyone came across something like this before of know how to get rid of this. I know I could always use a library, but I want to learn. Here is some code:
_containerScrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
_containerScrollView.contentSize = CGSizeMake(_containerScrollView.frame.size.width * 4, 0.0f);
_containerScrollView.pagingEnabled = YES;
[self.view addSubview:_containerScrollView];
UITableViewController *vc1 = [[UIViewController alloc] init];
UITableViewController *vc2 = [self.storyboard instantiateViewControllerWithIdentifier:#"trendingViewController"];
UITableViewController *vc3 = [self.storyboard instantiateViewControllerWithIdentifier:#"placesViewController"];
UITableViewController *vc4 = [self.storyboard instantiateViewControllerWithIdentifier:#"favoritesViewController"];
self.rallyViewControllers = [NSArray vc1, vc2, vc3, vc4, nil];
[self addViewControllers];
Other methods;
- (void)addViewControllers{
if (self.rallyViewControllers == nil) {
return;
}
for (int i = 0; i < [self.rallyViewControllers count]; i++) {
UIViewController* viewController = [self.rallyViewControllers objectAtIndex:i];
[self addChildViewController:viewController];
[viewController didMoveToParentViewController:self];
[_containerScrollView addSubview:viewController.view];
}
}
This is called in viewDidLayoutSubviews
- (void)configureFrames{
if (self.rallyViewControllers == nil) {
return;
}
CGFloat width = _containerScrollView.frame.size.width;
CGFloat height = _containerScrollView.frame.size.height;
for (int i = 0; i < [self.rallyViewControllers count]; i++) {
UIViewController *viewController = [self.rallyViewControllers objectAtIndex:i];
viewController.view.frame = CGRectMake(i * width, 0.0f, width, height);
}
}
I should state upfront that I didnt completely understand your description of
"table views began refusing to go all the way down and part of the
final table view cell stays trimmed by the end of the screen when the
scrolling ends."
My answer is based on an issue I faced before. My setup is a uitableview in the storyboard container view ( without any parent scrollview)
I faced this issue where part of the tableview was cut off and I could not see about 5 bottom rows.
Turns out I did not have any constraints setup between the parent container view and the tableview.
To determine if your tableviews are rendering fine, get your project running in XCode and then press on the below button
This button will then pause your app and give you a visual stack of the the different views that are currently rendered in your app. You can then see if any of the children ( in your case tableviews) are rendered outside the frame of the parent view in which case that portion will not be visible. This indicates that you either dont have constraints (or) the current constraints you have are incorrect.
I got it. The problem was when I added the view controllers views to the scroll view, they returned dimensions as if there was no navigation bar. But they were still positioned under the navigation bar, which caused total view to have 64 pt more height than the screen could show. when I manually subtracted 64 pt from views, and it was fixed. But since that is a very crude way of doing this, I then tried to fix it by fiddling with auto-layout, which ended up fine.
I had an UIViewControllerA created with xib for view reusability.
In the xib I simply added another red view to it and set its constraints to top,leading,trailing, and bottom space to red view's superview (which is my A's view).
Add A to another UIViewController B as B's ChildViewController by doing so:
// UIViewControllerB.m
UIViewControllerA *A = [UIViewControllerA alloc] initWithNibName:#"UIViewControllerA" bundle: nil]];
[A.view setFrame:CGRectMake(0,0, self.view.size.width, self.view.size.height/2)];
[self addChildViewController:A];
[self.view addSubview:A.view];
[self.A didMoveToParentViewController:self];
Nothing red or whatever showed up.
I did try [self.A.view setTranslatesAutoresizingMaskIntoConstraints:NO]; though
that seemed to make my constraints useless and actually did not bring up the red view.
Do I have to code the whole thing (UI elements & constraints creation) when I'm working with xib and need some extra view with autolayout?
Thanks for any advice!
The problem is this line:
[A.view setFrame:CGRectMake(0,0, self.view.size.width, self.view.size.height/2)];
Instead, give this view constraints.
When you insert a set of views that uses autolayout into a set of views that uses autolayout, you must use autolayout to position it.
I just added a separate view controller and xib in a project that uses storyboards throughout. I display it from inside another view controller with the usual code:
OtherVC *othervc = [[OtherVC alloc] initWithNibName:nil bundle:nil];
[self.view addSubView: othervc.view];
In portrait orientation, he xib displays and auto rotates properly right out of the box.
But when I display it when the iPad is already in landscape, the size of the view is portrait and positioned off to the left.
What's going on? There doesn't seem to be a way to add constraints to the view.
Thanks!
This is not the right way to present a separate viewController.
The problem is that you are adding a view on the actual view..but this view have a certain frame that will remain the same when you add it on the view..in both case (landscape and protrait). So, to understand, you should check the orientation and then set the frame of the view properly. But as i said, the way that you are using is wrong.
In your case you should use segue from storyboard.
Or, at max, by code but with something like:
OtherVC *othervc = [self.storyboard instantiateViewControllerWithIdentifier:#"Identifier"];
[self presentViewController:othervc animated:YES completion:nil];
where Identifier is set in your viewController in the storyboard by the inspector panel at the right.
Or, if you instead wanted to say "NIB" you should to do:
OtherVC *othervc = [[OtherVC alloc] initWithNibName:#"yourNibName" bundle:[NSBundle mainBundle]]; //Or your correct bundle but i guess will be this.
[self presentViewController:othervc animated:YES completion:nil];
So after this, if you are sure to have set both orientation on your project, your view will be in landscape.
Now you will use AutoLayout or normal mask rules without AutoLayout to manage the elements on the view.
I have a UISplitViewController in an iPad app. When something is selected from the table I want to fade in a modal view controller over the detail view. I can present it without a problem, but for some reason I can't get it to match the frame of the detail view. I would like it to stick to the detail view controller frame on rotation as well. Does anyone have any experience with this? This is my code to display. The detail view controller reference is set in the app delegate and passed down the table controllers.
QuestionViewController_iPad *questionView = [[[QuestionViewController_iPad alloc] initWithNibName:#"QuestionViewController_iPad" bundle:nil] autorelease];
questionView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
// Not quite
questionView.modalPresentationStyle = UIModalPresentationCurrentContext;
questionView.questionQuizCon = [QuestionQuizConnection firstQuestionForQuiz:quizCatCon.quiz];
// Maybe something like this?
[self.detailViewController presentModalViewController:questionView animated:YES];
When the modal view presents, it matches the size of the detail view controller, but it doesn't but it sits on the top left of the screen behind the master view controller. It also doesn't resize on rotation. I have the springs and struts set to auto size and fill. The height changes on rotation but it won't fill the width.
I couldn't get this to look right any way I tried it so I ended up just using view transitions to make it look like pages being torn off a notebook. That looks better anyway.
// Transition the view on as a subview.
[UIView transitionWithView:self.detailViewController.pageView duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:^ {
questionView.view.frame = CGRectMake(0, 0, self.detailViewController.pageView.frame.size.width, self.detailViewController.pageView.frame.size.height);
[self.detailViewController.pageView addSubview:questionView.view];
// Watch this one
self.detailViewController.currentQuestionViewController = questionView;
}
completion:nil];
After [self.detailViewController presentModalViewController:questionView animated:YES]; you should set center property and/or frame of questionView. Be sure that you set it after presenting modal view.
See below - the tableView cells are getting cut off. Why doesn't this work? The width of the popover is 240.
(In a subclass of UITableViewController)
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.frame = CGRectMake(0,0,200,200);
}
You have to specify the content size of the ui controller you are displaying. You can do it in 2 ways:
access the ui controller from your popover controller and set it size:
UIViewController* yourViewController = yourPopOverController.contentViewController;
yourViewController.contentSizeInViewController = CGSizeMake(300, 600);
check the checkbox "Use Explicit Size" for popover in the inspector of the viewController in storyboard
As you see the content ui controller is the one responsible of setting the size of your popover.
Have you tried specifying the popover's content size?
i.e.
self.popoverController.popoverContentSize = CGSizeMake(400, 500);
I've found that while popover's are "suppose" to adjust to the appropriate size based on the content view controller, this doesn't always work as well as it should.