I've been trying to solve this issue for the past couple of hours, searched SO and still to no avail.
I have a UIViewController which has a Container view inside (dragged in from Storyboards). The container view has a class associated that picks one of two other view controllers to display.
-(void)setDisplayMode:(EventsDisplayMode)displayMode {
switch (displayMode) {
case EventsDisplayModeGrid: {
// show grid
if (!gridViewController) {
gridViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"gridViewController"];
}
[UIView animateWithDuration:0.8 delay:0 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
if (listViewController)
[listViewController.view removeFromSuperview];
gridViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:gridViewController.view];
listViewController = nil;
} completion:^(BOOL finished) {
}];
break;
}
case EventsDisplayModeList: {
// show list
if (!listViewController)
listViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"listViewController"];
[UIView animateWithDuration:0.8 delay:0 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
if (gridViewController)
[gridViewController.view removeFromSuperview];
[self.view addSubview:listViewController.view];
gridViewController = nil;
} completion:^(BOOL finished) {
}];
break;
}
}
}
The above is the code in the container view controller. When either mode is set though, the view bleeds off the bottom of the screen on an iPhone 5s slightly, and on an iPhone 4S it's as though the view inside hasn't resized at all for the device. I've tried all sorts of combinations to resize the views - setting up constrains inside Storyboards for each of the controllers, manually taking off amounts from the height of views - nothing seems to work. Is there something obvious I'm missing?
Related
I have a scene which is built as on the attached screen
Scene
Depending on the selection of a button from the top bar, I'm loading a specific view controller inside a container view. When selection is changed or the user is tapping the 'Back' button at controller then should be removed an intrinsic content of the container.
Code for adding into container view:
if (self.containerVC != nil) {
[self removeController];
}
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
FirstViewController* firstVC = [storyboard instantiateViewControllerWithIdentifier:#"First"];
[self addChildViewController:firstVC];
[self.containerVieww addSubview:firstVC.view];
firstVC.view.frame = CGRectMake(0, 0, self.containerVieww.bounds.size.width, self.containerVieww.bounds.size.height);
[firstVC.view layoutSubviews];
[firstVC didMoveToParentViewController:self];
firstVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[UIView animateWithDuration:0.5 animations:^{
self.logViewHeight.constant = self.contentView.frame.size.height * 0.9;
[firstVC.view layoutSubviews];
}];
firstVC.delegate = self;
self.containerVC = firstVC;
Code for removing from container view:
[self.containerVC dismissViewControllerAnimated:YES completion:nil];
[UIView animateWithDuration:0.5 animations:^{
self.logViewHeight.constant = 0;
[self.view layoutIfNeeded];
}];
[self willMoveToParentViewController:nil];
[self removeFromParentViewController];
[self.containerVC.view removeFromSuperview]; // Caused layout destoying !!!
self.containerVC = nil;
After calling 'removeFromSuperview' is disappeared a 'Blue View' in my layout.
How to remove from the container view without destroying a complex layout?
I have a view controller with multiple child view controllers in it (set up using Storyboards), and I move the one on top to the right (with the status bar as well) to display the underlying sidebar view controller.
This works perfectly with frames, as shown below:
- (void)displaySidebar {
self.fullScreenSnapshotOverlay = [self takeFullScreenSnapshot];
[self.postsView addSubview:self.fullScreenSnapshotOverlay];
[self hideStatusBar];
[UIView animateWithDuration:0.4 animations:^{
CGRect newFrame = self.postsView.frame;
newFrame.origin.x += 200.0;
self.postsView.frame = newFrame;
}];
}
(hideStatusBar simply called the UIApplication method and layoutIfNeeded.)
Giving me this (perfect) result:
However, if in the Storyboard I go to the container view controller and make a constraint from its leading space to the left of the view controller it's embedded in, and then adjust that constant, it really messes up the navigation bar, I assume due to hiding the status bar and taking a screenshot. I'm using this code:
- (void)displaySidebar {
self.fullScreenSnapshotOverlay = [self takeFullScreenSnapshot];
[self.postsViewController.view addSubview:self.fullScreenSnapshotOverlay];
[self hideStatusBar];
[UIView animateWithDuration:0.4 animations:^{
self.postsViewControllerDistanceFromLeftSideConstraint.constant = 270.0;
[self.view layoutIfNeeded];
}];
}
Giving me this messed up result:
Now I know the simple thing to do would be to just continue with frames, but I'd like to learn how do it properly with Auto Layout. What am I doing wrong here?
I'm not sure how what I did is any different from what you're doing. I modified the code I posted to your other question (Why does hiding my status bar completely break my simple animation?) to what's below, and it worked fine.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self performSelector:#selector(displaySidebar) withObject:nil afterDelay:1];
}
-(void)displaySidebar {
self.snapshotView = [self takeSnapshot];
[self.PostsView addSubview:self.snapshotView];
[self hideStatusBar];
self.leftCon.constant = 270;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
}];
}
-(void)moveOutMenu { // called from a button in the menu controller
self.leftCon.constant = 0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
[[UIApplication sharedApplication] setStatusBarHidden:NO];
[self.snapshotView performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:0.01];
}];
}
-(UIView *)takeSnapshot {
UIView *v = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
return v;
}
-(void)hideStatusBar {
[[UIApplication sharedApplication] setStatusBarHidden:YES];
[self.view layoutIfNeeded];
}
What are all the constraints you have on the container view that you're moving? Maybe there's something different there (I have top, leading, bottom and width constraints on mine -- leftCon is the outlet to the leading constraint).
I have a brief for a share page which involves clicking on a share button and a modal view appearing over the top with some share functionality.
My issues is that i'd like the background of the modal view to be semi transparent and therefore show the view beneath. I've set the background properties of the modal layer and as the modal appears the layer beneath is briefly visible - and looks exactly as I require - but as soon as the cover transition is complete the background view is hidden - is there any way around this?
(Using IOS7 by the way)
Cheers
Update - #Tommaso Resti has kindly helped me try and figure this issue out - to explain what I've done so far - my main storyboard contains an unlinked uiview with the identifier 'ShareScreenView' - which I would like to add to my mainView as a transparent modal when clicking on a button. I have linked the button as an IBAction and added the following to my method -
- (IBAction)shareBtn:(id)sender {
NSLog(#"clicked");
/* Create your view off the screen (bottom) */
/* NEW EDIT */
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main_iPhone"
bundle: nil];
UIViewController *myModalController = [mainStoryboard instantiateViewControllerWithIdentifier:#"ShareScreenView"];
[myModalController.view setFrame:CGRectMake(0, 568, 320, 568)];
// [myModalController.view setFrame: CGRectMake(0, [[UIScreen mainScreen].bounds.size.height], [[UIScreen mainScreen].bounds.size.width], [[UIScreen mainScreen].bounds.size.height])];
/* Animate it from the bottom */
[UIView animateWithDuration:.5 animations:^{
CGAffineTransform move = CGAffineTransformMakeTranslation(0, -[UIScreen mainScreen].bounds.size.height);
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
myModalController.view.transform = move; /* UPDATED HERE */
NSLog(#"Atrying");
} completion:^(BOOL finished) {
NSLog(#"Adid try");
if(finished) {
NSLog(#"Animation completed");
}
}];
}
But I get an error on the line -
[myModalController.view setFrame: CGRectMake(0, [[UIScreen mainScreen].bounds.size.height], [[UIScreen mainScreen].bounds.size.width], [[UIScreen mainScreen].bounds.size.height])];
which simply states 'expected identifier' with an arrow pointing at height (see screen shot below)
so I tried adding the properties as follows -
[myModalController.view setFrame:CGRectMake(0, 568, 320, 568)];
now there are no errors - but nothing happens and no errors..
i suggest to use your own method:
something like this:
/* Create your view off the screen (bottom) */
/* NEW EDIT */
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
UIViewController *myModalController = [mainStoryboard instantiateViewControllerWithIdentifier:#"MyModalController"];
[myModalController.view setFrame: CGRectMake(0, [UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[self.view addSubview: myModalController.view]; /* UPDATED HERE! */
/* Animate it from the bottom */
[UIView animateWithDuration:.5 animations:^{
CGAffineTransform move = CGAffineTransformMakeTranslation(0, -[UIScreen mainScreen].bounds.size.height);
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
myModalController.view.transform = move; /* UPDATED HERE */
} completion:^(BOOL finished) {
if(finished) {
NSLog(#"Animation completed");
}
}];
than remove with this animation:
/* Reset animation */
[UIView animateWithDuration:.5 animations:^{
CGAffineTransform reset = CGAffineTransformIdentity;
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
myModalController.view.transform = reset; /* UPDATED HERE */
} completion:^(BOOL finished) {
if(finished) {
NSLog(#"Reset completed");
[myModalController.view removeFromSuperview];
}
}];
--- EDITED ---
Sorry, i forgot to add ".view " after myViewController.
i never try my code... my fault ;)
The example is updated!
You can create a View, which you slide in from the bottom and then make the view semi transparent.
You can use View Container to create your own ModalViewController and do animation just like #Tommaso Resti says
I have a single view App and want to show a new ViewController when pressing a nav bar button in the right hand side. I call this VC by this code:
- (IBAction)createEntryButton:(id)sender {
CreateEntryViewController *vc2 = [[CreateEntryViewController alloc] init];
[self presentViewController:vc2 animated:TRUE completion:nil];
}
This animation, however, brings the vc2 in from the bottom which seems counter-intuitive according to my UI. So my question is:
How can I make my vc2 appear from the right instead of the bottom with presentViewController?
Thanks.
the cleanest would be to use a navigationController for pushing and popping views..
if you are already in a NavigationController
[self.navigationCtroller pushViewController:vc2 animated:TRUE completion:nil]
if you aren't, adapt the code where your view controller is added to the window. If your VC is the rootWindowController and you are not using storyboarding, this is likely in your AppDelegate
if you use storyboards, adapt the storyboard so you are inside a navigation controller
ELSE if you don't want that for any reason: :) just manually animate in the 2. VC's view using [UIView animate:vc2.view ....]
written inline -- method names don't match but shows general approach:
UIView *v = vc2.view;
CGRect f = v.frame;
f.origin.x += self.view.frame.size.width; //move to right
v.frame = f;
[UIView animateWithDuration:0.5 animations:^{
v.frame = self.view.frame;
} completion:^(BOOL finished) {
[self presentViewController:vc2 animated:NO completion:nil];
}];
in the completion block present the view controller vc2 non-animated as you already did that yourself
This helped me,
- (void)presentNewViewController{
NewViewController *objNewViewController =[[NewViewController alloc]initWithNibName:#"NewViewController" bundle:nil];
UIView *tempNewVCView = [UIView new];
tempNewVCView = objNewViewController.view;
tempNewVCView.frame = self.view.frame;
CGRect initialFrame = self.view.frame;
initialFrame.origin.x = self.view.frame.size.width;
tempNewVCView.frame = initialFrame;
[self.view addSubview:tempNewVCView];
[UIView animateWithDuration:0.3 animations:^{
tempNewVCView.frame = self.view.frame;
} completion:^(BOOL finished) {
[self presentViewController:objNewViewController animated:NO completion:^{
}];
}];
}
I'm trying to work on a UIButton animation where the button moves to a point and then is set hidden to be true. However when I tried working on the following code, the button disappeared even before the animation was completed. Am I doing it correctly? Any suggestions?
[UIView animateWithDuration:0.8
animations:^{
selectedCurveIndex = 0;
[tradebutton moveTo:
CGPointMake(51,150) duration:0.8
option:curveValues[UIViewAnimationOptionCurveEaseInOut]];
}
completion:^(BOOL finished){
[tradeButton setHidden:TRUE];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"ButtonView"];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:vc animated:NO];
}];
You need to make sure that finished is set to YES before moving on.
Your button hides quickly because 0.8 is a quick animation duration. You will need to figure out another place to hide the button, or you can
Try this:
[UIView animateWithDuration:0.8
animations:^{
selectedCurveIndex = 0;
[tradebutton moveTo:
CGPointMake(51,150) duration:0.8
option:curveValues[UIViewAnimationOptionCurveEaseInOut]];
}
completion:^(BOOL finished){
if ( finished )
{
[tradeButton performSelector:#selector(setHidden:) withObject:#"YES" afterDelay:3.0];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"ButtonView"];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:vc animated:NO];
}
}];
The problem is that you create a second, inner animation block in the moveTo:duration:option: method, and you set all of the animatable properties in that inner block. You don't set any animatable properties in the outer block.
That means that the system immediately thinks that the outer animation has finished, and calls the completion block right away. Meanwhile, the inner animation block is still going.
Stop using moveTo:duration:option:. It saves you almost nothing, and ends up giving you trouble like this. Throw it out and try something like this instead:
[UIView animateWithDuration:0.8 animations:^{
tradeButton.frame = (CGRect){ CGPointMake(51, 150), tradeButton.bounds.size };
} completion:^(BOOL finished) {
tradeButton.hidden = YES;
// etc.
}];
Note that UIViewAnimationOptionCurveEaseInEaseOut is the default for most animations.