I would like to know how can I load a new nib file after finishing with UIImagePicker Controller. So after the user takes a picture from the camera or albums, i would like to load a new nib for the user to do some editing. Below is the didFinishPickingMediaWithInfo. I can load an image to the current UIImageView or even send out and alertview, but even if I tried loading a new nib, it just goes back to currentview nib and no errors. Bear in mind that I'm a total ios noob, so if the method use is wrong, please let me know. Thanks in advance.
p.s. Just to add, even if I manage to load new nib, how do I pass the information from the previous nib? E.g. if I choose an image from nib2, how to pass it to nib3?
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
imageOverlay.image = [UIImage imageNamed:#"mask_overlay1.png"];
[imageOverlay release];
// Displaying image to the imageView
imageView.image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
// Tried to load a new nib
UIView *currentView = self.view;
// Get the underlying UIWindow, or the view containing the current view.
UIView *theWindow = [currentView superview];
//remove the current view and replace with myView1
[currentView removeFromSuperview];
// set up an animation for the transition between the views
CATransition *animation = [CATransition animation];
[animation setDuration:0.5];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[theWindow layer] addAnimation:animation forKey:#"createPhotoView"];
}
I have no idea what your app's workflow is like, but if you need to display a new view after an image is chosen, you should probably do it by either pushing a new view controller on to a navigation controller, or by presenting it as a modal view.
This allows you to easily return to the previous screen where you were asked to pick a photo.
Let's say that for your app, you decide to use a UINavigationController.
You would initialize a navigation controller with your first view controller as the root view controller.
Then, in your UIImagePicker delegate method, you would have something like this:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// Initialize your new view controller
CustomViewController *controller = [[CustomViewController alloc] initWithNibName:#"SecondView" bundle:nil];
// Pass your custom view controller the image you just selected
controller.valueToPass = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
}
You create a subclass of UIViewController called CustomViewController, and pass it values by creating properties you can assign to (like valueToPass in my example).
EDIT:
It is possible to just switch the visible view of a view controller. It is as simple as changing the value of self.view. You could put two UIViews in the same XIB file, and put IBOutlets for both in your controller. You could have a header that looks like this:
#interface MyController : UIViewController {
IBOutlet UIView *view1;
IBOutlet UIView *view2;
}
// Follow this with properties for all of those IBOutlets as well
Then, in your controller code:
- (IBAction)switchViews {
if ([self.view isEqualTo:view1]) {
self.view = view2;
} else {
self.view = view1;
}
}
This works, but as far as I am aware, does not allow transitions. You could instead do this:
- (IBAction)switchViews:(id)sender {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:NO];
if ([[secondaryView superview] isEqual:mainView]) {
[secondaryView removeFromSuperview];
} else {
[self.view addSubview:secondaryView];
}
[UIView commitAnimations];
}
Both of these options work, and allow you to use the same view controller to control both views. However, if the views perform different tasks, they should be associated with different controllers. Using different controllers is similar if you set up a controller as a property in your header:
- (IBAction)switchViews:(id)sender {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:NO];
if (self.secondaryController) {
[self.secondaryController.view removeFromSuperview];
self.secondaryController = nil;
} else {
self.secondaryController = [[SecondaryController alloc] initWithNibName:#"SecondView" bundle:nil];
self.secondaryController.valueToPass = #"I am passing this value!";
[self.view addSubview:self.secondaryController.view];
}
[UIView commitAnimations];
}
Related
Right now I am using a segue from storyboard to push a view controller and there is just the one push transition. How can I imitate the "Pop" transition in code? Can I do this while still using storyboard for my other transitions in place now?
UPDATE
I tried what is suggested in the first comment here, with some changes. Here's what I have:
UIViewController *dst = [self destinationViewController];
UIViewController *src = [self sourceViewController];
[dst viewWillAppear:YES];
[dst viewDidAppear:NO];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGRect f = CGRectMake(-screenBounds.size.width, 0, screenBounds.size.width, screenBounds.size.height);
dst.view.frame = f;
f.origin.x = screenBounds.size.width;
src.view.frame = f;
[UIView transitionFromView:src.view
toView:dst.view
duration:0.3
options:UIViewAnimationOptionTransitionNone
completion:^(BOOL finished){
[dst viewDidAppear:YES];
UINavigationController *nav = src.navigationController;
[nav popViewControllerAnimated:NO];
[nav pushViewController:dst animated:NO];
}];
This is working almost how I want, but the original viewcontroller is just disappearing instead of sliding to the right.
You can create Segue type "Custom" on your stroyboard and create a new UIStoryboardSegue class named "popSegue" In the popSegue.m file add this:
-(void)perform{
UIViewController *sourceViewContreoller = [self sourceViewController];
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionFromLeft]; //or kCATransitionFromRight
[animation setDuration:0.25];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:
kCAMediaTimingFunctionEaseIn]];
[sourceViewContreoller.navigationController.view.layer addAnimation:animation forKey:#"animateOpacity"]; //or key=#"fadeTransition"
[sourceViewContreoller.navigationController popViewControllerAnimated:YES];
[CATransaction commit];
}
In the storyboard editor Select the segue and change the Segue Class to "popSegue".
Set the Identifier to "popSegue".
Try this and comment for your result
In my application, I have navigation controller with two view controllers: MainController and DetailController.
In main view controller I have an image view and I want to push DetailController with animation like GarageBand menu when I tap on image view(look to 20 second of this video).
So, question is how to implement fade-in animation.
Here's the code:
//calls on tapping on image
- (void)tapImageView:(UIImageView *)sender {
DetailController *detailController = [[DetailController alloc] initWithNibName:#"controller" bundle:nil];
//configure detail controller
//here comes animation
[self.navigationController pushViewController:detailViewController animated:NO];
[detailController release];
}
I can animate image fading out:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
//sender is UIImageView
sender.frame = self.view.frame;
imageView.alpha = 0;
[UIView commitAnimations];
but anytime I push my DetailViewController to navigationcontroller, that animation doesn't show.
How to implement GarageBand's menu switching animation?
Thanks.
How about using paging with UIScrollView.
I think it is better than using UIView animation.
I have a UIView that contains a subview called menuView managed by a MenuViewController.
I wrote that code :
- (void) viewDidLoad
{
[self.menuView setFrame:CGRectOffset(self.menuView.frame, 0.0, self.menuView.frame.size.height)];
[super viewDidLoad];
}
- (void) viewDidAppear:(BOOL)animated
{
[UIView beginAnimations:#"SomeAnimation" context:nil];
[UIView setAnimationDuration:2.0];
[UIView setAnimationDelegate:self];
[UIView setAnimationTransition:UIViewAnimationTransitionNone forView:self.menuView cache:YES];
[self.menuView setFrame:CGRectOffset(self.menuView.frame, 0.0, -self.menuView.frame.size.height)];
[UIView commitAnimations];
[super viewDidAppear:animated]; // tried at begining too
}
But when loaded, no animation is visible... I also tried with viewWillAppear with no change.
it is called outside MenuViewController with :
- (IBAction) showMenu
{
MenuViewController* menuController = [[MenuViewController alloc] initWithNibName:#"Menu" bundle:nil];];
[self.view addSubview:menuController.view];
// [menuController release]; for try
}
What's the problem ?
P.S. : What I want to do is when the view is displayed, some part of that view (the menuView) move. That view (partially transparent) is intended to cover a superview that is owned by another ViewController.
Are you calling the viewDidAppear method from your view controller? Some controllers, such as the UINavigationController, will take care of that, but if you're using a custom controller, you'll need to call it. Typically, you would call viewWillAppear, then add the view, the call viewDidAppear.
So your code block would be:
- (IBAction) showMenu
{
MenuViewController* menuController = [[MenuViewController alloc] initWithNibName:#"Menu" bundle:nil];];
[menuController viewWillAppear:YES];
[self.view addSubview:menuController.view];
[menuController viewDidlAppear:YES];
[menuController release];
}
Can you confirm that self.menuView is actually properly initialized and is not nil?
Perhaps you should first call the super initialization of your method ?
[super viewDidAppear:animated]
I need to switch views by swiping with a curl animation for transition.
I tried PageControl (and other approaches -.-), but it's not what I need for several reasons, so I'll go for the GestureRecogntion, but I stuck.
My problem by now is the architecture. There is the firstVC, calling the SecondVC, onto which I add the subviews (of a third VC) to, which should be swipeable. I don't know if it's possible at all to swipe through subviews from another VC or if it's the code or the IB setup that won't do the job (It's my first time with gesture recogntion)
So by now I just loaded 4 dummy subviews when the secondVC loads. My GR-Code (just for the leftswipe, but rightswipe is more or less the same..)
- (void)handleSwipeFrom:(UISwipeGestureRecognizer *)recognizer {
NSInteger viewToBeShown = 0;
NSString *nextSubviewStr = [NSString stringWithFormat: #"view%d", (viewToBeShown)];
if (recognizer.direction == UISwipeGestureRecognizerDirectionLeft){
if (currentSubview >0) {
viewToBeShown = currentSubview-1;
nextSubviewStr = [NSString stringWithFormat: #"view%d", (viewToBeShown)];
Ubg *nextSubview = [[Ubg alloc] initWithNibName:nextSubviewStr bundle:nil];
[self.view removeFromSuperview];
[self.view addSubview:nextSubview.view];
Could you tell me if that could should basically work (and it's just my IB setup that's not correct)? This is driving me nuts! If you need any other information, just let me know.
Thank you for your time and patience!
This is the code used for curl animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 1];
//setting animation for the current view
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.navigationController.view cache:YES];
//Next ViewController to push
nextPage *detailViewController = [[nextPage alloc] initWithNibName:#"nextPage" bundle:nil];
//Push the next viewcontroller to NavigationController
[self.navigationController pushViewController:detailViewController animated:NO];
[detailViewController release];
//Start the Animation
[UIView commitAnimations];
I'm trying to present a UIViewController from the side.
The only thing that Present Modal can do is Verticle Slide in.
Any body have any ideas about this?
Let me know' thanks
To be anal about the MVC, its really the View your moving and not the controller.
I would recommended the way of doing this would be to use a navigation controller, it's animation is a horizontal slide by default and you get a navigation stack for free- this means that you have back buttons auto generated and, title and button properties that you can set, although these can be hidden easily is desired.
Using a navigation controller:
create a UINavigationsController property in your parent controller, syth, alloc and init it appropriately. Then you can load the controllers in in any order you want and it looks after the navigation.
Here is a good tutorial on NavControllers (usually they are used with UITableViewControllers but don't have to be)
Peng's example is an animation and I should note that it removes the parent view (and depending on your design might not just remove the 'currentView' - as your/a top view might be a subView) so if your navigating back you would have to handle this yourself.
I did this and it worked, though I don't know if there is a more official way to do it (UIVIewAimationTransition doesn't have a slide option):
UIView *currentView = self.view;
UIView *theWindow = [currentView superview];
[currentView removeFromSuperview];
CATransition *animation = [CATransition animation];
[animation setDuration:0.5];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[theWindow layer] addAnimation:animation forKey:#"SwitchToView1"];
I just gave this answer to another SO question that was very similar, but here it is again, in case folks looking end-up here, instead.
All of the ViewControllers in my app inherit from MyViewController which, in addition to some other default behaviours, has this property:
#property(readwrite, nonatomic) BOOL slideFromSide;
And this code:
- (void) presentViewController: (UIViewController*) vc animated: (BOOL) flag completion: (void (^)(void)) completion
{
BOOL slideIn = NO;
if ([vc isKindOfClass: [MyViewController class]])
{
MyViewController *svc = (MyViewController*) vc;
slideIn = svc.slideFromSide;
}
if (slideIn)
{
[self addChildViewController: vc];
[self.view addSubview: vc.view];
CGRect frame = vc.view.frame;
frame.origin.x = frame.size.width;
vc.view.frame = frame;
frame.origin.x = 0;
[UIView animateWithDuration: 0.33
animations: ^{
vc.view.frame = frame;
}
];
}
else
{
[super presentViewController: vc animated: flag completion: completion];
}
}
- (IBAction) backAction: (id) sender
{
if (_slideFromSide)
{
CGRect frame = self.view.frame;
frame.origin.x = frame.size.width;
[UIView animateWithDuration: 0.33
animations: ^{
self.view.frame = frame;
}
completion:^(BOOL finished) {
[self removeFromParentViewController];
}
];
}
else
{
[self dismissViewControllerAnimated: YES completion: nil];
}
}
Then, in the ViewControllers where I want to slide-in, I have:
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil];
if (self)
{
self.slideFromSide = YES;
// Whatever else you want to do
}
return self;
}
Calling a new ViewController is just like normal:
WhateverViewController *vc = [WhateverViewController alloc] initWithNibName: nil bundle: nil];
[self presentViewController: vc animated: YES completion: nil];