Hiding master view in split view app..? - iphone

I have created split view based ipad app, where master view is table view while Detail view display images.. I need to display the image fit to screen 100% in landscape mode.
This could be on button event or double tap event.. How should i do that.
Thanks in advance.

You can accomplish what you want by using a secondary window in your app that you display on-demand on top of your main window that contains the split view.
Create a new UIWindow & a new UIViewController. Add the UIViewController's view to your new window, set the window level to a positive value (1 or more) so that it is on top of your main window, then put the new window onscreen. If you set the window background color to [UIColor clearColor] and position your image in a view inside the new UIViewController directly on top of the image that is in the detail view then the user won't notice that anything new has happened. You can then animate the image frame up to fullscreen or do whatever you want. We sometimes use this technique to support drag & drop or our own custom modal view controllers but it'll work for your purpose too.
Here's an example:
#interface MyViewController : UIViewController #end
#interface AppDelegate : NSObject <UIApplicationDelegate> {
MyViewController *overlayController;
UIWindow *overlayWindow;
UIWindow *window; // the main window that contains your splitview
UINavigationController *navigationController; // or split view contoller, whatever, your main controller
}
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
#implementation MyViewController
- (void) loadView {
self.view = [[[UIView alloc] initWithFrame: CGRectZero] autorelease];
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.view.backgroundColor = [UIColor redColor];
}
#end
#implementation AppDelegate
#synthesize window, navigationController;
- (void) click:(id) sender {
[overlayController.view removeFromSuperview];
[overlayController release];
overlayController = nil;
overlayWindow.hidden = YES;
[overlayWindow release];
overlayWindow = nil;
}
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Add the navigation controller's view to the window and display.
// standard stuff...
[self.window addSubview: navigationController.view];
[self.window makeKeyAndVisible];
// add the overlay window
// note that both the overlay window and controller are retained until we dismiss
// the window, this is important!
overlayWindow = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].applicationFrame]; // or [UIScreen mainScreen].bounds, depending on what you want
overlayController = [MyViewController new];
overlayController.view.frame = overlayWindow.bounds;
UIButton *button = [UIButton buttonWithType: UIButtonTypeRoundedRect];
[button addTarget: self action: #selector(click:) forControlEvents: UIControlEventTouchUpInside];
[button setTitle: #"Done" forState: UIControlStateNormal];
button.frame = CGRectMake( 0, 0, 100, 50 );
button.center = overlayController.view.center;
[overlayController.view addSubview: button];
// the controller's view is the first and only view in the
// new window. this ensures you get rotation events. Add any subviews
// that will appear in the new window to overlayContoller.view
[overlayWindow addSubview: overlayController.view];
[overlayWindow setWindowLevel: 1];
[overlayWindow makeKeyAndVisible];
return YES;
}
- (void)dealloc {
[overlayController release];
[overlayWindow release];
[navigationController release];
[window release];
[super dealloc];
}
#end

Related

UIButton created programmatically but doesn't show up on view (addSubview was called)

Have an AppDelegate and a MainViewController.
In MainViewController the UIButton was created, AppDelegate sets a background image and should show it on MainViewController. That's pretty much it but I can't see the UIButton.
Just for alignment purpose I created an IBOutlet and connected the button in IB.
MainViewController.h
#property (strong, nonatomic) IBOutlet UIButton *searchBtn;
MainViewController.m
#synthesize searchBtn;
AppDelegate.m
#synthesize mainVC;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ViewController > setup:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.mainVC = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.window.rootViewController = self.mainVC;
self.window.backgroundColor = [UIColor whiteColor];
// Buttons > Set background images:
[self.mainVC.searchBtn setImage:[UIImage imageNamed:#"search.png"] forState:UIControlStateNormal];
[self.mainVC.view addSubview:self.mainVC.searchBtn];
[self.window makeKeyAndVisible];
return YES;
}
First you don't need IBOutlet if you are creating it programmatically.
Second you probably want to move the creation of the button in viewDidLoad of your view controller rather than in your AppDelegate. It's your view controller's business.
Third you should probably alloc init your button if you create it programmatically:
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(...)];
[button setBackgroundImage:someImage];
[button addTarget:self action:#selector(something:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
something like that.
You should be adding buttons in your MainViewController class, not the AppDelegate first off.
You should also set the background of the view in MainViewController, not the AppDelegate.
It should look like this:
AppDelegate.m
#synthesize mainVC;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ViewController > setup:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.mainVC = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.window.rootViewController = self.mainVC;
[self.window makeKeyAndVisible];
return YES;
}
In your MainViewController.m's viewDidLoad put this
- (void)viewDidLoad {
[super viewDidLoad];
// Buttons > Set background images:
[searchBtn setBackgroundImage:[UIImage imageNamed:#"search.png"] forState:UIControlStateNormal];
//If you adding the button in Interface Builder you don't need to add it again
//[self.view addSubview:self.mainVC.searchBtn];
}

Switching custom views programmatically (pushing and popping)

In iOS, my views work individually but I can't switch between them.
Now after a lot of google-ing around I've fond that the navigation based app would work great with the stack for views. The problem is all my views are nib/xib-less and custom tailored in the source code. Because of that I need my own UINavigationController and push and pop views by hand/code. Since every tutorial is either nib/xib and IB bound or just a mash of code snippets I need a concrete example how to do it.
A simple example with 2 programmatically created view (can be empty just have to use loadView instead of initializing with a nib/xib) and a working stack (a push and a pop of the views like: load app,create some root view if needed, push one view and from that view push the second one and then pop them) would be awesome, or at least a tutorial in that way with the whole source of the project and not snippets.
Thanks in advance.
EDIT: After some extra thinking, a little more clarification wouldn't be bad. My app will basically consist of 5 or 6 views which will be called form their respective previous view, i.e. a drill-down app.
Here's a brief code, only the essential parts:
CodeViewsPushingAppDelegate.m
#import "CodeViewsPushingAppDelegate.h"
#import "ViewNumberOne.h"
#implementation CodeViewsPushingAppDelegate
#synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
UINavigationController *navController = [[UINavigationController alloc] init];
ViewNumberOne *view1 = [[ViewNumberOne alloc] init];
[navController pushViewController:view1 animated:NO];
[self.window addSubview:navController.view];
[self.window makeKeyAndVisible];
return YES;
}
ViewNumberOne.h
#import <UIKit/UIKit.h>
#interface ViewNumberOne : UIViewController
{
UIButton *button;
}
- (void)pushAnotherView;
#end
ViewNumberOne.m
#import "ViewNumberOne.h"
#import "ViewNumberTwo.h"
#implementation ViewNumberOne
- (void)loadView
{
[super loadView];
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(110, 190, 100, 20);
[button setTitle:#"Push Me!" forState:UIControlStateNormal];
[button addTarget:self action:#selector(pushAnotherView) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)pushAnotherView;
{
ViewNumberTwo *view2 = [[ViewNumberTwo alloc] init];
[self.navigationController pushViewController:view2 animated:YES];
[view2 release];
}
ViewNumberTwo.h
#import <UIKit/UIKit.h>
#interface ViewNumberTwo : UIViewController
{
UILabel *label;
}
#end
ViewNumberTwo.m
#import "ViewNumberTwo.h"
#implementation ViewNumberTwo
- (void)loadView
{
[super loadView];
label = [[UILabel alloc] init];
label.text = #"I am a label! This is view #2";
label.numberOfLines = 2;
label.textAlignment = UITextAlignmentCenter;
label.frame = CGRectMake(50, 50, 200, 200); //whatever
[self.view addSubview:label];
}

Can't add UINavigationController programmatically to a TabBar Application

I have an application for which I use TabBar template. In one of viewcontrollers I want to add a uinavigationcontroller. I declare it in the .h file;
#import <UIKit/UIKit.h>
#import "AnotherViewController.h"
#interface SecondViewController : UIViewController <UINavigationControllerDelegate> {
UIButton *UIButton *gotoAnotherView;;
AnotherViewController *anotherView;
UINavigationController *navigationController;
}
#property(nonatomic,retain) UIButton *UIButton *gotoAnotherView;;
#property(nonatomic,retain) AnotherViewController *anotherView;
#property(nonatomic,retain) UINavigationController *navigationController;
-(void)buttonPressed:(id)sender;
#end
And here's my .m file
#import "SecondViewController.h"
#implementation SecondViewController
#synthesize navigationController, anotherView, gotoAnotherView;
-(void)buttonPressed:(id)sender {
anotherView = [[AnotherViewController alloc]init];
[navigationController pushViewController:anotherView animated:YES];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
navigationController = [[UINavigationController alloc ]initWithRootViewController:self];
[navigationController.navigationBar setFrame:CGRectMake(0, 0, 320, 44)];
[self.view addSubview:navigationController.navigationBar];
gotoAnotherView = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 40, 40)]; //kategoributonlari
UIImage *image = [UIImage imageNamed:#"1.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(110, 5, 100, 20);
[self.view addSubview:imageView];
[kategori1 setBackgroundImage:image forState:UIControlStateNormal];
[kategori1 addTarget:self
action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:kategori1];
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
However I can see from the navigation bar that the navigationcontroller goes one level deeper(back button appears) but the main view remains the same with my gotoAnotherView button.
I think that I might not make the navigationcontroller control the whole view.
Instead of trying to do this in code, edit the XIB for your main window (with the UITabBarController). Drag out a UINavigationController from the Library onto the tab bar. This will create a new bar item for you, with a UINavigationController. Select the UIViewController nested in the new UINavigationController, and on the Identity tab set the Class to your view controller, and on the Attributes tab specify the name of the nib file to load.
You don't need to use IB. You can setup everything in code. First create your view controllers tab1ViewController, tab2ViewController, etc. then create the navigation controller with the root view controllers of tab1ViewController etc. and then add these controllers to the tab bar controller.
Here is a sample:
UINavigationController *tab1NavigationController = [[UINavigationController alloc] initWithRootViewController:tab1ViewController];
UINavigationController *tab2NavigationController = [[UINavigationController alloc] initWithRootViewController:tab2ViewController];
UITabBarController rootViewController = [[UITabBarController alloc] init];
rootViewController.viewControllers = [NSArray arrayWithObjects:tab1NavigationController, tab2NavigationController, nil];
[tab1NavigationController release];
[tab2NavigationController release];

Stacked modal UIViewControllers don't animate as per doc?

In short, I have a root controller RootController presenting a modal navigation controller showing Controller1, which itself presents a modal navigation controller showing Controller2.
I want to dismiss Controller1 and Controller2 at the same time by sending the root controller a dismissModalViewControllerAnimated: message.
I expected to see an animation of Controller2 being dismissed (or rather its navigation controller) and NOT see Controller1 in the process, taking me back to the root controller, as per the documentation:
If you present several modal view
controllers in succession, and thus
build a stack of modal view
controllers, calling this method on a
view controller lower in the stack
dismisses its immediate child view
controller and all view controllers
above that child on the stack. When
this happens, only the top-most view
is dismissed in an animated fashion;
any intermediate view controllers are
simply removed from the stack. The
top-most view is dismissed using its
modal transition style, which may
differ from the styles used by other
view controllers lower in the stack.
However, Controller2 is being dismissed instantaneously without animation and I can see Controller1 being dismissed (with an animation).
It might be a misunderstanding on my part of the documentation. If it is, could someone help me find a solution?
Here is a sample code that will demonstrate my problem (all superfluous code removed, no memory management, no error handling...):
// AppDelegate.h:
#import <UIKit/UIKit.h>
#import "RootController.h"
#interface AppDelegate : NSObject <UIApplicationDelegate> {
IBOUTLET UIWindow *window;
RootController *rootController;
}
#end
// AppDelegate.m:
#import "AppDelegate.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
rootController = [[RootController alloc] init];
[window addSubview:rootController.view];
[window makeKeyAndVisible];
return YES;
}
#end
// RootController.h:
#import <UIKit/UIKit.h>
#import "Controller1.h"
#interface RootController : UIViewController {
Controller1 *controller1;
UINavigationController *controller1navigationController;
UIButton *button;
}
#end
// RootController.m:
#import "RootController.h"
#implementation RootController
- (void)testMe:(id)target {
controller1 = [[Controller1 alloc] init];
controller1navigationController = [[UINavigationController alloc] initWithRootViewController:controller1];
[self presentModalViewController:controller1navigationController animated:YES];
}
- (void)loadView {
[super loadView];
button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
[button setTitle:#"Test me" forState:UIControlStateNormal];
button.frame = CGRectMake(50, 200, 220, 50);
[button addTarget:self action:#selector(testMe:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
#end
// Controller1.h:
#import <UIKit/UIKit.h>
#import "Controller2.h"
#interface Controller1 : UIViewController {
Controller2 *controller2;
UINavigationController *controller2navigationController;
UIButton *button;
}
#end
// Controller1.m:
#import "Controller1.h"
#implementation Controller1
- (void)testMe:(id)target {
controller2 = [[Controller2 alloc] init];
controller2navigationController = [[UINavigationController alloc] initWithRootViewController:controller2];
[self presentModalViewController:controller2navigationController animated:YES];
}
- (void)loadView {
[super loadView];
button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
[button setTitle:#"Test me 1" forState:UIControlStateNormal];
button.frame = CGRectMake(50, 156, 220, 50);
[button addTarget:self action:#selector(testMe:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
self.view.backgroundColor = [UIColor greenColor];
}
#end
// Controller2.h:
#import <UIKit/UIKit.h>
#interface Controller2 : UIViewController {
UIButton *button;
}
#end
// Controller2.m:
#import "Controller2.h"
#implementation Controller2
- (void)testMe:(id)target {
[self.parentViewController.parentViewController.parentViewController dismissModalViewControllerAnimated:YES];
}
- (void)loadView {
[super loadView];
button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
[button setTitle:#"Test me 2" forState:UIControlStateNormal];
button.frame = CGRectMake(50, 156, 220, 50);
[button addTarget:self action:#selector(testMe:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
self.view.backgroundColor = [UIColor redColor];
}
#end
Thanks for helping me find a solution to this problem.
You really shouldn't use such a big stack of viewcontrollers. The problem with this approach is that all those viewcontrollers stay in memory until you dismiss the first one which can cause memory warnings if those controllers get heavy.
If you still want to use that approach I would suggest using the delegate design pattern. So basically add a protocol for the first controller:
#protocol RootControllerDelegate
-(void) dismissModal;
#end
and assign a property to the next controllers
#property (nonatomic, assign) id <RootControllerDelegate> rootdelegate;
then just call [self.rootdelegate dismissModal] where you want them to disappear. This will visually look like only the last controller disappearing animated.
The better way to do this is making a RootViewController and adding the other viewcontrollers as subviews to it where you can remove them from memory when switching, see How does UITabBarController work?

UITabBarController rotation problem with popViewControllerAnimated and selectedIndex (iPhone SDK)

This is a very important auto rotate issue and easy to reproduce.
My application has a UITabBarController. Each tab is a UINavigationController. Auto rotation is handled with normal calls to shouldAutorotateToInterfaceOrientation and didRotateFromInterfaceOrientation.
The interface rotates normally until I call UIViewController.popViewControllerAnimated and change UITabBarController.selectedIndex.
Steps to reproduce:
Create a demo Tab Bar Application.
Add the following code to the App Delegate .h file:#import <UIKit/UIKit.h>
#interface TestRotationAppDelegate : NSObject {
UIWindow *window;
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
// Redefine the interface to cach rotation messages
#interface UITabBarController (TestRotation1AppDelegate)
#end
Add the following code to the App Delegate .m file:#import "TestRotationAppDelegate.h"
#implementation TestRotationAppDelegate
#synthesize window;
#synthesize tabBarController;
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
return YES;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
-(void)dealloc {
[tabBarController release];
[window release];
[super dealloc];
}
#end
#implementation UITabBarController (TestRotation1AppDelegate)
-(void)viewDidLoad {
[super viewDidLoad];
// Add a third tab and push a view
UIViewController *view1 = [[[UIViewController alloc] init] autorelease];
view1.title = #"Third";
UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:view1] autorelease];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObjectsFromArray:self.viewControllers];
[array addObject:nav];
self.viewControllers = array;
// Push view2 inside the third tab
UIViewController *view2 = [[[UIViewController alloc] init] autorelease];
[nav pushViewController:view2 animated:YES];
// Create a button to pop view2
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(50, 50, 220, 38);
[button setTitle:#"Pop this view" forState:UIControlStateNormal];
[button addTarget:self action:#selector(doAction) forControlEvents:UIControlEventTouchUpInside];
[view2.view addSubview:button];
}
-(void) doAction {
// ROTATION PROBLEM BEGINS HERE
// Remove one line of code and the problem doesn't occur.
[self.selectedViewController popViewControllerAnimated:YES];
self.selectedIndex = 0;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#end
The interface auto rotates normally until you tap the button on tab #3.
Your help will be geatly appreciated!
iPhone SDK 3.2 solves this issue.
With previous SDK use [self.selectedViewController popViewControllerAnimated:NO].