Navigation bar is removed when pushing a viewcontroller from another storyboard - ios

I have many storyboards in my project to have modules with specific functionalities. In one of my storyboard, I have a navigation controller, which push the initial view controller of another storyboard. When I push it, the navigation bar is removed and there is no way to get this specific bar back. When I put another navigation controller in my new storyboard, the navigation bar is resetted with an ugly transition (it comes from the right and replace the older one).
This is how I push my new storyboard's view controller :
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:aStoryboardName bundle:nil];
UIViewController *SideBarInitialViewController = [storyboard instantiateInitialViewController];
UIStoryboardSegue *segue = [[GDFromRightCustomSegue alloc] initWithIdentifier:aSegueIdentifier source:aSource destination:SideBarInitialViewController];
[segue perform];
I perform a custom segue as well to get rid of the basic animation (the view coming from below) :
UIView *sourceView = [self.sourceViewController view];
UIView *destinationView = [self.destinationViewController view];
CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width;
destinationView.frame = CGRectMake(screenWidth, 0.0, screenWidth, screenHeight);
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
[window insertSubview:destinationView aboveSubview:sourceView];
[UIView animateWithDuration:0.4 animations:^{
destinationView.frame = CGRectOffset(destinationView.frame, -screenWidth, 0.0);
sourceView.frame = CGRectOffset(sourceView.frame, -screenWidth, 0.0);
} completion:^(BOOL finished){
[self.sourceViewController presentViewController:self.destinationViewController animated:false completion:nil];
}];
Is there a way to push the new storyboard without animate the navigation bar, or even better, to have the older navigation controller in my new storyboard ?

In your source storyboard drag a new UIViewController and then drag a ** Modal segue** to this new UIViewController from your source ViewController. Click on this segue and then in the attributes Inspector add a Identifier of segue (let say "newSegue") Identifier must be unique. Also set segue type to "Custom " and write "newSegue" in Segue Class
Now add a catagory on UIStoryBoardSegue with name newSegue and in the .m file write these two methods.
- (id) initWithIdentifier:(NSString *)identifier
source:(UIViewController *)source
destination:(UIViewController *)destination
{
return [super initWithIdentifier:identifier
source:source
destination:[[UIStoryboard storyboardWithName:#"YourDestinationStoryBoardName" bundle:nil] instantiateInitialViewController ]];
}
- (void)perform
{
UIViewController *source = (UIViewController *)self.sourceViewController;
[source presentViewController:self.destinationViewController
animated:YES
completion:Nil];
}
Now in your source ViewController when you want to presenth new View Controller write this line
[self performSegueWithIdentifier:#"newSegue" sender:nil];
Must Remember to replace "YourDestinationStoryBoardName" with your actual destination StoryBoard name in the above function.
Try this Hope this will work fine.

Related

Custom Segue Animation Flicker

I am building an application using UISplitViewController as my root view controller (as prescribed by Apple). However, I needed a custom view for login / management to be displayed prior to the UISplitViewController, so I created a custom UIStoryboardSegue that calls some custom animations. I am attempting to recreate the push / pop segues through a modal segue, without actually pushing an popping view controllers. I've implemented everything correctly, however, at the end of my animation I have a flicker. Here is a gif of it:
Here is my custom Segue's code:
- (void)perform {
UIViewController *srcViewController = (UIViewController *) self.sourceViewController;
UIViewController *destViewController = self.destinationViewController;
UIView *prevView = srcViewController.view;
UIView *destView = destViewController.view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:destView aboveSubview:prevView];
[destView enterRight:0.1 then:^{
[destView removeFromSuperview];
[srcViewController.presentingViewController dismissViewControllerAnimated: NO completion:nil];
}];
}
And here is my custom animation (Implemented as a category on UIView):
-(void)enterRight:(float)delay then:(void(^)(void))after
{
CGPoint moveTo = self.center;
CGPoint moveFrom = self.center;
// Grab a point from off the screen
CGFloat simpleOffscreen = [UIScreen mainScreen].bounds.size.width;
// come from off the right side (+)
moveFrom.x = moveFrom.x + simpleOffscreen;
self.center = moveFrom;
self.hidden = NO;
[UIView animateWithDuration:0.5
delay:delay
usingSpringWithDamping:1
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseIn
animations:^
{
self.center = moveTo;
}
completion:^(BOOL finished)
{
if (after) after();
}
];
}
As you can see in the Segue, I am animating the view into the current view controller, then without animation presenting the actual destination view controller. I think this is where the flicker is introduced, yet I am unsure about how to go about preventing this.
My Storyboard for this custom segue is
Anyone know how to implement this?

IOS Custom sliding UIViewcontroller from left to right and caused segue error

Due to I have to slide UIViewController from left to right by a finger swipe, I have created a custom uiviewcontroller transition, after slide and clicked the navigation inside the destination controller, error occurred.
Terminating app due to uncaught exception 'NSGenericException',
reason: 'Could not find a navigation controller for segue 'stepsPage'.
Push segues can only be used when the source controller is managed by
an instance of UINavigationController.'
- (void) returnHome
{
UIStoryboard *storyboard = self.storyboard;
MainViewController *destVC = [storyboard instantiateViewControllerWithIdentifier:#"main"];
// Get the views.
UIView * toView = destVC.view;
UIView * fromView = self.view;
// Get the size of the view area.
CGRect viewSize = fromView.frame;
// Add the toView to the fromView
[fromView.superview addSubview:toView];
// Position it off screen.
toView.frame = CGRectMake( -320 , viewSize.origin.y, 320, viewSize.size.height);
NSLog(#" viewSize.origin.y %f", viewSize.size.height);
[UIView animateWithDuration:0.3 animations:
^{
// Animate the views on and off the screen. This will appear to slide.
fromView.frame =CGRectMake( 320 , viewSize.origin.y, 320, viewSize.size.height);
toView.frame =CGRectMake(0, viewSize.origin.y, 320, viewSize.size.height);
}
completion:^(BOOL finished)
{
if (finished)
{
// Remove the old view from its parent.
[fromView removeFromSuperview];
//I use it to have navigationnBar and TabBar at the same time
//self.tabBarController.selectedIndex = indexPath.row+1;
}
}];
NSLog(#"swipe");
}
Segue Function in the destination view controller
- (void) prepareForSegue: (UIStoryboardSegue *) segue sender: (id) sender
{
GeneralViewController *GeneralView = (GeneralViewController*)segue.destinationViewController;
NSString *titleString;
// Set the photo if it navigates to the PhotoView
if ([segue.identifier isEqualToString:#"stepsPage"])
{
titleString = #"Steps";
GeneralView.goalStr = [NSString stringWithFormat:#"%d", [mySetting integerForKey:#"dailyStep"]];
GeneralView.currentStr = [NSString stringWithString:_stepLabel.text];
GeneralView.percentage = grpPercent.step;
}
else
{
return;
}
}
Error you are getting you dont have Naviation Controller around controller through which you want to push it to next controller
Below approaches can be applied to such situation
Approach 1 - Visually add Navigation Controller
You need to your first controller or your existing controller must be embedded in UINavigation
controller - you can do it in xcode 5 by going to Editor -> EmbedIn -> Select Navigation Controller
If you dont want Navigation to appear in your app you can use below line
self.navigationController.navigationBar.hidden =YES;
Approach 2 - Programatically add Navigation Controller
if you want to do it programatically you can do it as follows
MainViewController *destVC = [storyboard instantiateViewControllerWithIdentifier:#"main"];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:destVC];

PrepareforSegue in the initial view control

In Storyboard I have a TabBarController set as the initial view controller which connects ("view controller" relationship) to a Navigation Controller, which in turn connects to a View controller (iphone5VC).
How is it possible to programmatically change the view controller iphone5VC to iphone4VC? I have to decide which of iphone5VC or iphone4VC I will display depending on the phone size (iphone4, 5)
Thanks a lot to both of you. I finally decided to have only one Storyboard and use specific viewcontrollers on an adhoc basis when the 3.5 screen really needs to have a slightly different layout.
What I did is:
Added <UITabBarControllerDelegate> in the viewcontroller .h file from which the user presses on the TabBar to select the view.
Added in the viewdidLoad of the .m file:
UITabBarController *tbc = self.tabBarController;
[tbc setDelegate:self];
and then added in the same file:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
UIStoryboard *myStoryBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
CGSize result = [[UIScreen mainScreen] bounds].size;
if (tabBarController.selectedIndex == 1) // button # 2 pressed
{
if (result.height == IPHONE4_HEIGHT)
{
navController = (UINavigationController *) [myStoryBoard instantiateViewControllerWithIdentifier:#"ViewControlleriphone4"];
[self presentViewController:navController animated:NO completion:nil];
}
else
{
navController = (UINavigationController *) [myStoryBoard instantiateViewControllerWithIdentifier:#"ViewControlleriphone5"];
[self presentViewController:navController animated:NO completion:nil];
}
}
}
If I'm reading your question correctly, you want to include a "check" in your app where the result will set the size of your view controllers, and I'm assuming the layout of the views contained within, based upon which phone the user has. If I have this correct, check out this thread. Also, I would strongly recommend using Auto Layout, which will automatically place the views inside your view controller, regardless of screen size and layout (portrait/landscape).
If I'm not understanding your question, maybe paste a screenshot or some code. Hope this helps, good luck!
So if i am understanding you correctly, you really want to load a separate storyboard (and associated viewController)depending on the device type.
if so, what you need to do is have your main storyboard only contain the initial TabBarController, Navigation Controller, and a subclass of UIViewController we'll call dynamicViewController. The dynamicViewController will load the appropriate storyboard based on the device type. Obviously the various storyboards will need to exist (in the code below, the storyboards are named iphoneV4.storyboard and iphoneV5.storyboards)
So your dynamicViewController, simply needs the following -(void)viewDidLoad method;
- (void)viewDidLoad {
[super viewDidLoad];
UIViewController __unused * targetViewController = nil;
CGRect screenBounds = [[UIScreen mainScreen] bounds];
UIStoryboard *targetStoryboard = (screenBounds.size.height == 568) ? [UIStoryboard storyboardWithName:#"iphoneV5" bundle:nil] : [UIStoryboard storyboardWithName:#"iphoneV4" bundle:nil];
targetViewController = [targetStoryboard instantiateInitialViewController];
if (self.parentViewController && ![self.parentViewController isKindOfClass:UITabBarController.class] && ![self.parentViewController isKindOfClass:UINavigationController.class]) {
// replace self with the target view controller
[self.parentViewController addChildViewController:targetViewController];
[self.view.superview insertSubview:targetViewController.view aboveSubview:self.view];
[self.view removeFromSuperview];
[self removeFromParentViewController];
} else { // tab bars, nav controllers, and modal dialogs
[self addChildViewController:targetViewController];
CGRect f = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
targetViewController.view.frame = f;
[self.view addSubview:targetViewController.view];
}
}

Nice slide transition between non-fullscreen and fullscreen UIViewController

I have a view controller which is not fullscreen (has a status bar) and want to present a modal view controller which is fullscreen.
If I hide the status bar at the beginning of the animation (parent's viewWillDisappear or modal's viewWillAppear) then for a moment the parent will be visible without a status bar, looking like a bug.
If I do it at the end of the animation (parent's viewDidDisappear or modal's viewDidAppear) then the status bar will be visible for a moment over the modal view, i.e. it won't appear as the modal view "covered it".
Is there a way to do this nicely?
edit:
One possibility would be to create a UIWindow with windowLevel=alert for at least the duration of the animation. The sample iAd ad seems to cover the status bar nicely without another window, so it must be possible somehow.
Another fun little project. This was the best I could come up with. It's not too bad if you don't mind using your own container controller to manage presenting/dismissing view controllers. I try to do things in a general way but this could be rolled into an app w/ the ContainerViewController if desired.
Note that I only implemented the equivalent of UIModalTransitionStyleCoverVertical. You can customize the animation however you like as well.
Relevant animation code:
- (void)presentViewController:(UIViewController *)viewControllerToPresent
{
// do nothing if no controller
if (!viewControllerToPresent) return;
[__viewControllers addObject:viewControllerToPresent];
CGRect toFrame = viewControllerToPresent.view.frame;
toFrame.origin = CGPointMake(0, CGRectGetMaxY(self.view.bounds));
viewControllerToPresent.view.frame = toFrame;
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionNone
animations:^{
[[UIApplication sharedApplication] setStatusBarHidden:viewControllerToPresent.wantsFullScreenLayout withAnimation:UIStatusBarAnimationSlide];
[self.view addSubview:viewControllerToPresent.view];
viewControllerToPresent.view.frame = [UIScreen mainScreen].applicationFrame;
}
completion:nil];
}
- (void)dismissViewController
{
// nothing to dismiss if showing first controller
if (__viewControllers.count <= 1) return;
UIViewController *currentViewController = [__viewControllers lastObject];
UIViewController *previousViewController = [__viewControllers objectAtIndex:__viewControllers.count - 2];
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionNone
animations:^{
[[UIApplication sharedApplication] setStatusBarHidden:previousViewController.wantsFullScreenLayout withAnimation:UIStatusBarAnimationSlide];
CGRect toFrame = currentViewController.view.frame;
toFrame.origin = CGPointMake(0, CGRectGetMaxY(self.view.bounds));
currentViewController.view.frame = toFrame;
}
completion:^(BOOL finished) {
[currentViewController.view removeFromSuperview];
[__viewControllers removeLastObject];
}];
}
I do that in my app with this code:
[[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleBlackOpaque];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation: UIStatusBarAnimationSlide ];
DocumentListViewController * dl = [[DocumentListViewController alloc] initWithNibName:#"DocumentListView" bundle:nil] ;
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:dl];
[dl release];
// Go to the list of documents...
[[self.view superview] addSubview:nav.view];
nav.view.alpha = 0.0 ;
[self hideActivityAlert];
[UIView animateWithDuration:1.0 animations:^{
nav.view.alpha = 1.0; } completion:^(BOOL A){
[self.view removeFromSuperview];
[self release];} ];
The status bar is presented shoftly while the animation occurs.
You have to be sure that the first view, when status bar is going hidden will fill the space. Use the property autoresizingMask with proper value.
Here's a solution that seems to work. You can derive the viewcontroller you want to present modally from my TSFullScreenModalViewController, or you can just implement the code right in the view controller itself.
#interface TSFullScreenModalViewController : UIViewController
{
UIWindow* _window;
}
- (void) presentFullScreenModal;
#end
#implementation TSFullScreenModalViewController
- (void) viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear: YES];
[_window resignKeyWindow];
[_window release];
_window = nil;
}
- (void) presentFullScreenModal
{
UIViewController* rvc = [[UIViewController new] autorelease];
rvc.view.backgroundColor = [UIColor clearColor];
_window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds] ;
_window.windowLevel = UIWindowLevelStatusBar+1;
_window.backgroundColor = [UIColor clearColor];
_window.rootViewController = rvc;
[_window makeKeyAndVisible];
[UIApplication sharedApplication].statusBarHidden = YES;
[rvc presentModalViewController: self animated: YES];
[UIApplication sharedApplication].statusBarHidden = NO;
}
#end
Derive your modal view controller, like this:
#interface MyModalViewController : TSFullScreenModalViewController
{
}
- (IBAction) onDismiss:(id)sender;
#end
Use it from another view controller, like this:
- (IBAction) onShowModal:(id)sender
{
MyModalViewController* mmvc = [[MyModalViewController new] autorelease];
[mmvc presentFullScreenModal];
}
Finally, dismiss your view controller as you normally would:
- (IBAction) onDismiss:(id)sender
{
[self dismissModalViewControllerAnimated: YES];
}
Might be a bit of a hack but have you considered:
Take a screenshot programatically of the first view with the status bar (see this SO question)
Create a new view which displays the image you just took in fullscreen (using UIImage's initWithFrame)
Hide the status bar
Present the modal view controller
Then to dismiss the modal view, just reverse the steps.
EDIT:
Won't work for this because you can't take screenshots of the status bar.
It could be as simple as delaying the presentation of your modalViewController using performSelector:withDelay:
Tell the status bar to animate out and then launch the modal controller with the right delay so it coincides with the status bar animation.

iPhone app - adding another view

I am working on an iPhone app but found that I require another view / window to get the user to input and save data / information there.
How do I add another view? Do I add it in interface builder and then link it in the main app delegate or will it have its own .h and .m files.
I selected a window view app to start with, do I need to start over with a flip side view app or can this just be added in anyway if I have the correct code there.
manny thanks
Carl
The Window app is perfect for you. In your AppDelegate file, you should have a section like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//instantiate the venue view controller object
YourViewController *yourViewController = [[YourViewController alloc] initWithNibName:#"YourView" bundle:[NSBundle mainBundle]];
// Configure and show the window
[window addSubview:[yourViewController view]];
[window makeKeyAndVisible];
}
This is the part of the code that declares, allocates and adds your custom view to the window. You have a couple choices for how to add the second view. You can either add it in place of this one, or add it after this one using a Navigation Controller. To add the navigation controller, change the above method to look like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//instantiate the venue view controller object
YourViewController *yourViewController = [[YourViewController alloc] initWithNibName:#"YourView" bundle:[NSBundle mainBundle]];
UINavigationController *yourViewControllerWrapper = [[UINavigationController alloc] initWithRootViewController: yourViewController];
// Configure and show the window
[window addSubview:[yourViewControllerWrapper view]];
[window makeKeyAndVisible];
}
There, we create your custom view, then wrap it in a navigation controller. The navigation controller is what gets added to the window. Next the code to switch to the second view would look like this, assuming you switch views on a button press:
-(IBAction)switchViewController{
MySecondViewController *secondViewController = [[MySecondViewController alloc] init];
[self.navigationController pushViewController:secondViewController];
}
Of course, you should replace the line
MySecondViewController *secondViewController = [[MySecondViewController alloc] init];
with the proper way of instantiating your second view controller. This could be from a nib file like above, or programmatically.
As far as creating the view files, you should create a nib in Interface builder for the layout of everything, then create a .h and .m file for the ViewController code itself.
you can also display new frame instead of new view. It is easier sometimes, as you don;t have to pass parameters - you are in one class:
CGRect frame = okresView.frame;
frame.origin.x = frame.size.width;
if ( [okresView superview] == nil )
{
[self.view addSubview:okresView];
}
okresView.frame = frame;
[okresDataTableView reloadData]; // przeĊ‚adowanie tabeli na subwidoku
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.5];
frame.origin.x = 0;
okresView.frame = frame;
[UIView commitAnimations];
if you want new subview, you can use a few methods - just download few applications from XCode help and check how they do this. Nice example are in 'Elements' and 'UICatalog' application where you have flipped view and other examples.
// Create and push another view controller.
UIViewController *myViewController = [[UIViewController alloc] init];
myViewController.title = #"My First View";
myViewController.view.backgroundColor = [UIColor redColor];
//to push the UIView.
[self.navigationController pushViewController:myViewController animated:YES];

Resources