Master/Detail Project With Preceding View - iphone

I need to create a split view application that starts with basic view that I customize manually. Then I need to transition to the SplitView or push the master/detail table views onto the stack for the phone implementation.
The strategy I was planning to use would be placing the basic view into the detail pane on the SplitView controller, and while it was there just hide the side panel and button for the left pane in their respective orientations.
Is there a better way? Can I use a "plain" view as my root view, then switch it programmatically to a UISplitView?
For the phone version - this isn't really a problem. Since the navigation controller is the root view controller - I can just push more views onto the stack.
For the iPad - you cannot push a UISplitView controller onto the Navigation stack. I'd really like to do this so I have some concept of "back". I can create it programmatically - but before I do - I'd be interested in some other options if they exist.
I want to use Storyboards for this application - and the target version is iOS 5 - for ARC.

I've done this by replacing the root of the app. As first screen I had a LoginViewController, and when the login was successful, switched that ViewController with a UISplitViewController. You can do this animated too.
Edit:
Here is my code from the UIStoryboardSegue subclass:
- (void) perform
{
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
UIViewController *sourceViewController = (UIViewController *)self.sourceViewController;
UISplitViewController *destinationViewController = (UISplitViewController *)self.destinationViewController;
UIWindow *window = appDelegate.window;
window.rootViewController = destinationViewController;
window.rootViewController = sourceViewController;
[UIView transitionWithView:sourceViewController.view.window
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
window.rootViewController = destinationViewController;
}
completion:^(BOOL finished){
}];
}

try this code:
you can add your LoginViewcontroller as A root view-controller in Delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[LogInViewController alloc] initWithNibName:#"LogInViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
and your loginButton Action:
-(IBAction)loginclick:(id)sender
{
objAppdelegate = (yourProjectnameDelegate *) [[UIApplication sharedApplication]delegate];
NSMutableArray *array = [NSMutableArray array];
HomeSpilitView = [[[UISplitViewController alloc] init]autorelease];
HomeMster = [[HomeSpilitViewController alloc] initWithNibName:#"HomeSpilitViewController" bundle:nil];
masterNavigationController = [[[UINavigationController alloc] initWithRootViewController:HomeMster] autorelease];
HomeMster.title=#"Title home";
masterNavigationController.navigationBar.tintColor =[UIColor colorWithRed:255/255.0 green:108/255.0 blue:61/255.0 alpha:0.1];
[array addObject:masterNavigationController];
HomeDetailsViewController *HomeDetailsViewControllers = [[HomeDetailsViewController alloc] initWithNibName:#"HomeDetailsViewController" bundle:nil];
detailNavigationController = [[[UINavigationController alloc] initWithRootViewController:HomeDetailsViewControllers] autorelease];
detailNavigationController.navigationBar.tintColor =[UIColor colorWithRed:255/255.0 green:108/255.0 blue:61/255.0 alpha:0.1];
HomeDetailsViewControllers.title=#"details title";
HomeMster.objHomeDetailsViewcontroller=HomeDetailsViewControllers;
HomeSpilitView.delegate = HomeDetailsViewControllers;
[array addObject:detailNavigationController];
[HomeSpilitView setViewControllers:array];
[objAppdelegate.window setRootViewController:HomeSpilitView];
}
//===for animation
UIInterfaceOrientation interfaceOrientation = HomeSpilitView.interfaceOrientation;
NSString *subtypeDirection;
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
subtypeDirection = kCATransitionFromTop;
}
else if (interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
subtypeDirection = kCATransitionFromBottom;
}
else {
subtypeDirection = kCATransitionFromRight;
}
[objAppdelegate.window setRootViewController:HomeSpilitView];
CATransition *animation = [CATransition animation];
[animation setDuration:0.5];
[animation setType:kCATransitionPush];
[animation setSubtype:subtypeDirection];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[objAppdelegate.window layer] addAnimation:animation forKey:#"SwitchToView1"];

Related

view not in the window hierarchy

I have created a function in app delegate which i run from a view but when I comeback to run the function again it gives me
<ResultViewController: 0x757dfc0> on <ViewController: 0x71325c0> whose view is not in the window hierarchy!
Error
the app delegate code is opening a viewcontroller
code is
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *view1 = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
[self.window setRootViewController:view1];
[self.window makeKeyAndVisible];
return YES;
}
-(void)specify
{
ResultViewController *res = [[ResultViewController alloc]init];
CATransition *transition = [CATransition animation];
transition.duration = 0.3;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[self.window.layer addAnimation:transition forKey:nil];
[self.window.rootViewController presentModalViewController:res animated:NO];
}
Not running your code I am guessing it is because the window you are trying to add to does not exist on the view hierarchic, you are just creating views and adding them to the screen - you need to grab the actual screen itself.
Try something like
UIViewController *presentController = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
ViewController *view1 = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
[presentController presentViewController:view1 animated:YES completion:nil];
While creating the class make UIViewController its parent class.
It seems UIViewController is not the parent class of your class there is no .view of your object
You should present modal view controller in navigationController of rootViewController.
[self.window.rootViewController.navigationController presentModalViewController:res animated:NO];
So, if you really want to present modal view controller into rootViewController, remember:
If the window has an existing view hierarchy, the old views are removed before the new ones are installed.
Your first attempt to show modal viewController replace view hierarchy but self.window.rootViewController did not change and it is not in the window hierarchy anymore.
Or something like that.

How to move to another view without using a button

My first view displays an image and action indicator while web-servers and database function are run in that background. I want the application to go to my tab view when the functions have been completed. How do I do this?
Here is what the views look like.
What I have tried:
TabBarViewController *tab = [[TabBarViewController alloc]init];
[self presentViewController:tab animated:NO completion:nil];
and
[self performSegueWithIdentifier:#"first" sender:self];
Please can you help my to understand how to do this. I have spent many hours googling this problem and couldn't work out how to do it.
Thanks
EDIT: Added Code
Since you are downloading data you can get a call when the downloading request gets finished
like the method below
- (void)requestFinished:(ASIHTTPRequest *)request
and in this method you can very well present your TabBarViewController.
You can use GCD to make this happen.
For instance in your firstViewController where you trigger downloading you can do:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[model downloadData];
dispatch_sync(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"YourSegueIdentifier" sender:self];
});
});
I assume your downloadData method is synchronous, if not you can use notifications in your model. Once data is retrieved you could postNamedNotification from NSNotificationCenter and in firstViewController you could register for notification and after receiving it you would call performSegueWithIdentifier
You Can Declare A separate Method for that.
Call the below method when your function completes.
[self performSelector:#selector(gotonext:) withObject:nil afterDelay:4.0];
-(void)gotonext;
{
TabBarViewController *tab = [[TabBarViewController alloc]init];
[self presentViewController:tab animated:NO completion:nil];
}
Take one splashView Image at starting, like bellow...
#interface AppDelegate : UIResponder <UIApplicationDelegate>{
UIImageView *splashView;
}
#property (nonatomic, retain) UIImageView *splashView;
#end
in AppDelegate.m file...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
splashView = [[UIImageView alloc] initWithFrame:iphoneFrame];
splashView.image = [UIImage imageNamed:#"Default"];
[self.window addSubview:splashView];
[self.window makeKeyAndVisible];
UIViewController *viewController1 = [[[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil] autorelease];
UINavigationController *navviewController1=[[UINavigationController alloc]initWithRootViewController:viewController1];
navviewController1.title = #"FirstTitle";
// navviewController1.navigationBarHidden=YES;
UIViewController *viewController2 = [[[yourviewController2 alloc] initWithNibName:#"yourviewController2" bundle:nil] autorelease];
UINavigationController *navviewController2=[[UINavigationController alloc]initWithRootViewController:viewController2];
// navviewController2.navigationBarHidden=YES;
navviewController2.title = #"SecondTitle";
UIViewController *viewController3 = [[[yourviewController3 alloc] initWithNibName:#"yourviewController2" bundle:nil] autorelease];
UINavigationController *navviewController3=[[UINavigationController alloc]initWithRootViewController:viewController3];
// navviewController3.navigationBarHidden=YES;
navviewController3.title = #"ThirdTitle";
//..... and so on depend on your requirement
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:navviewController1, navviewController2 , navviewController3 ,nil];
[self performSelector:#selector(loadViewIphone) withObject:nil afterDelay:2.0];//**add this line at your all data are loading completed**
}
else
{
splashView = [[UIImageView alloc] initWithFrame:ipadFrame];
splashView.image = [UIImage imageNamed:#"Default_iPad"];
[self.window addSubview:splashView];
[self.window makeKeyAndVisible];
[self performSelector:#selector(loadViewIpad) withObject:nil afterDelay:2.0];
}
[self.window makeKeyAndVisible];
return YES;
}
-(void)loadViewIphone
{
[splashView removeFromSuperview];
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
CATransition *animation = [CATransition animation];
[animation setDelegate:self];
[animation setType:kCATransitionFromBottom];
[animation setDuration:1.0];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:
kCAMediaTimingFunctionEaseInEaseOut]];
[[self.window layer] addAnimation:animation forKey:#"transitionViewAnimation"];
[self.window makeKeyAndVisible];
}
i hope this help you...
Hm... What if you put
TabBarViewController *tab = [[TabBarViewController alloc]init];
[self presentViewController:tab animated:NO completion:nil];
In
dispatch_async(dispatch_get_main_queue(), ^{
//stop the loader once the database stuff has finished and get rid of the text
[[self firstLoader]stopAnimating];
self.downloadingLabel.text = #"";
});
UPDATE: If you want to do this sync
dispatch_sync(a_queue, ^{ wait_for_me(); });
And after that present your VC.

left to right transition in view based application on moving from one view controller to another

MyView *view=[[[MyView alloc] init] autorelease];
[view setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:view animated:YES];
I have used flip transition on moving from one view controller to another.but my requirement is from left to right transition. Please help me to way out this problem thanks in advance.
here is my code:
You need to add QuartzCore Framework and then import #import <QuartzCore/QuartzCore.h>
MyView *next = [[MyView alloc] init];
CATransition *animation = [CATransition animation];
[self presentModalViewController:next animated:NO];
[animation setDuration:0.40];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
//[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
[[next.view layer] addAnimation:animation forKey:#"SwitchToView1"];
[next release];
I assume you are dismissing a view controller 2 from view controller 1. In view controller 2 you are using this
[self dismissModalViewControlleAnimated: NO];
Now In the 1st view controller, import of "QuartzCore" header and add viewWillAppear method with code
#import <QuartzCore/QuartzCore.h>
(void)viewWillAppear:(BOOL)animated {
CATransition *animation = [CATransition animation];
[animation setDelegate:self];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setDuration:0.50];
[animation setTimingFunction:
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[self.view.layer addAnimation:animation forKey:kCATransition];
}
- (void)slideView:(UIView*)view direction:(BOOL)isLeftToRight {
CGRect frame = view.frame;
frame.origin.x = (isLeftToRight) ? -320 : 320;
view.frame = frame;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
frame.origin.x = 0;
view.frame = frame;
[UIView commitAnimations];
}
Why don't you use a UINavigationController and push the UIViewController instead of presenting it modally?
Edit:
To change your view-based app into a UINavigationController just add this to your AppDelegate
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *nvcontrol = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[self.window addSubview:nvcontrol.view];
Yes, you should do this through Navigational Controller.
Here is some code to help you, if you want to do it through Navigational Controller.
In AppDelegate.h:
#interface AppDelegate : UIResponder <UIApplicationDelegate,UINavigationControllerDelegate>{
UINavigationController *navController;
}
In AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// ViewController is your FirstViewController which loads over Window.
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
self.window.rootViewController = _viewController;
navController =[[UINavigationController alloc] initWithRootViewController:_viewController];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
Then in your ViewController.m, in your button tapped function, you can do this:
NextViewController *nextController = [[NextViewController alloc] initWithNibName:#"NextViewController" bundle:nil];
[self.navigationController pushViewController:nextController animated:YES];
And that's all.
try this
[self.navigatationController pushViewController:view animated:YES];

Correct way to show Login Screen followed by UITabbarController menu

I need to implement the following and I wanted to know the correct way to do it.
when the iPhone application launches, I need to show a logo image for 2 seconds followed by showing a login screen that allows the person to login or create an account. Once the person logs in, i need to show a tabbarcontroller menu options.
This is how I'm currently doing it:
In the AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
LoginViewController *viewController0 = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
UINavigationController *aNavigationController0 = [[UINavigationController alloc] initWithRootViewController:viewController0];
self.window.rootViewController = aNavigationController0;
// I also implement an iVar of the UITabBarController here...
// ....
}
The #implementation:
#implementation LoginViewController
- (IBAction)createNewAccountButtonClicked:(id)sender {
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
delegate.window.rootViewController = delegate.tabBarController;
}
So, my questions are:
Is this the correct way to show the tabbar for my purpose?
In this scheme of things, I cannot show the logo animated. Any pointers on how to do this?
The code below assumes you're using ARC, if you're not then you'll need to do your MRC.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.tabBarController = [[UITabBarController alloc] initWithNibName:nil bundle:nil];
self.window.rootViewController = self.tabBarController;
LoginViewController *loginViewController= [[LoginViewController alloc] initWithNibName:nil bundle:nil];
loginViewController.delegate = self;
UINavigationController *loginNavCont = [[UINavigationController alloc] initWithRootViewController:loginViewController];
[self.tabBarController presentModalViewController:loginNavCont animated:NO];
UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default"]];
[self.window addSubview:splashScreen];
[UIView animateWithDuration:0.5
delay:2.0
options:0
animations:^{
splashScreen.alpha = 0.0;
}
completion:^(BOOL finished) {
[splashScreen removeFromSuperview];
}];
[self.window makeKeyAndVisible];
return YES;
}
- (void)loginViewControllerShouldBeDismissed:(UIViewController *)viewController
{
[self.tabBarController dismissModalViewControllerAnimated:YES];
}

iPhone Pushing View Controller in a left direction

I have an app that has a centre view with two views off to each side of it. I want to have two navigation bar buttons, left and right which push a new navigation controller onto the view from the left or the right.
When you change views by pushing a new view using the pushviewController: method of NavigationController, the view appears to slide in from the right. how do i change this to slide in from the left?
I have done change animation direction when we push viewcontroller.
you can change animation type here [animation setSubtype:kCATransitionFromRight];
ViewController *elementController = [[ViewController alloc] init];
// set the element for the controller
ViewController.element = element;
// push the element view controller onto the navigation stack to display it
CATransition *animation = [CATransition animation];
[[self navigationController] pushViewController:elementController animated:NO];
[animation setDuration:0.45];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromRight];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
[[elementController.view layer] addAnimation:animation forKey:#"SwitchToView1"];
[elementController release];
Instead of using a navigation controller, I would just move the view.
CGRect inFrame = [currentView frame];
CGRect outFrame = firstFrame;
outFrame.origin.x -= inFrame.size.width;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[newView setFrame:inFrame];
currentView setFrame:outFrame];
[UIView commitAnimations];
I don't think you can explicitly define sliding direction in UINavigationControllers. What you might be able to do is pop the current view off the navigation stack to show the prior view, which would animate in the manner you want. However this may be complex if you want to have different view controllers appear depending on what you do on the current view.
If your workflow is not too complicated, you can hold a reference to the prior view controller in the current view controller. depending on what you do on the current view (like select a table view cell), you can change whatever data you need in the prior view controller, and then call
[self.navigationController popViewController];
or whatever the correct method is (i think that's pretty close to how it is). that would let you move down the nav stack with the animation you want, which works if your nav stack has a set number of views on it.
to what Reed Olsen said: you must only hook up one button, that starts the slide up to the same method and add a BOOL that tracks if the view is shown or not. all you need to do is set the origin properly.
- (IBAction)slideMenuView
{
CGRect inFrame = [self.view frame];
CGRect outFrame = self.view.frame;
if (self.viewisHidden) {
outFrame.origin.x += inFrame.size.width-50;
self.viewisHidden = NO;
} else {
outFrame.origin.x -= inFrame.size.width-50;
self.viewisHidden = YES;
}
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[self.menuView setFrame:inFrame];
[self.view setFrame:outFrame];
[UIView commitAnimations];
}
To get the "pointy" type button you need to use a different method.
In your AppDelegate:
UITableViewController *first = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
UITableViewController *second = [[SomeOtherViewController alloc] initWithStyle:UITableViewStylePlain];
NSArray *stack = [NSArray arrayWithObjects: first, second, nil];
UINavigationController *nav = [[UINavigationController alloc] init];
[nav setViewControllers:stack animated:NO];
You can inherit RTLNavigationController:UINavigationController and overwrite these functions.
- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
DummyViewController*dvc = [[DummyViewController alloc] init];
[super pushViewController:viewController animated:NO];
[super pushViewController:dvc animated:NO];
[dvc release];
[super popViewControllerAnimated:YES];
}
and
- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
UIViewController *firstViewController = [super popViewControllerAnimated:NO];
UIViewController *viewController = [super popViewControllerAnimated:NO];
[super pushViewController:viewController animated:animated];
return firstViewController;
}
And in application delegate:
navCon = [[RTLNavigationController alloc] init];
rootViewController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
rootViewController.contextDelegate = self;
DummyViewController *dvc = [[DummyViewController alloc]init];
[navCon pushViewController:dvc animated:NO];
[dvc release];
[navCon pushViewController:rootViewController animated:NO];
[self.window addSubview:navCon.view];
Pushing will be from left to right and popping from right to left