Popover view for iPhone using XCode 5 - iphone

I wanted to reuse the popover for iPhone described in this video which is exactly what I need.
The problem is that I couldn't bind a UIViewController property to the popover's UIViewController like in the video.
One difference with the video is that it has been made using XCode 4.2 and I'm using XCode 5.
So the question is: How to make a popover for iPhone like in the video on XCode 5?
Here is the XCode 5 project I am struggling with.

I figured out a way to get popover to work on iPhone and iPad programmatically !
Create a category to make popover available on iPhone (more details here)
//UIPopover+Iphone.h
#interface UIPopoverController (overrides)
+ (BOOL)_popoversDisabled;
#end
//UIPopover+Iphone.m
#implementation UIPopoverController (overrides)
+ (BOOL)_popoversDisabled { return NO;
}
#end
Create the button which will show the popover and implement the method it calls
ExampleUIViewController.h
#interface ExampleViewController : UIViewController <UIPopoverControllerDelegate>
#property (strong, nonatomic) UIButton *detailButton;
#property (nonatomic, retain) IBOutlet UIPopoverController *poc;
UIPopoverController poc has to be held in an instance variable, more details here.
ExampleUIViewController.m
- (void)viewDidLoad {
_detailButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_detailButton addTarget:self
action:#selector(showPop:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_detailButton];
}
-(void)showPop:(UIButton *)button {
UIViewController *detailsViewController = [[DetailsViewController alloc] initWithNibName:#"DetailsViewController" bundle:nil];
self.poc = [[UIPopoverController alloc] initWithContentViewController:detailsViewController];
[self.poc setDelegate:self];
[self.poc presentPopoverFromRect:_detailButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}
Create the UIViewController that will contain what's displayed inside the popover (called DetailsViewController in the example)
Simply create it in your project by a right click -> New File -> Objective c class -> UIViewController and tick the box "With XIB".
Then a popover will appear right next to the button when tapped.
Tested OK on iOs5 and above.

Related

iOS5 Custom Tab Bar

I am new to Iphone and I have started an application in which I have added a custom tab bar which has to load to some particular page only. The tab bar works as per my expectation. Now the problem is that, when I navigate to other pages the tab bar keeps on showing and it cause serious problem for me...
Here is my implementation
In .h:
#import <UIKit/UIKit.h>
#class MainMenuViewController;
#interface RoutineListViewController : UIViewController<UITabBarDelegate>{
MainMenuViewController *homeBtn;
UITabBar *mainTabBar;
UIViewController *routineTabViewController;
UIViewController *calendarTaViewController;
UIViewController *editTabViewController;
}
#property (nonatomic, retain) IBOutlet UITabBar *mainTabBar;
#property (nonatomic, retain) IBOutlet UIViewController *routineTabViewController;
#property (nonatomic, retain) IBOutlet UIViewController *calendarTabViewController;
#property (nonatomic, retain) IBOutlet UIViewController *editTabViewController;
- (IBAction)goToHome:(id)sender;
#end
In .m, i am implementing the tab as:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
switch (item.tag) {
case 1:
if (routineTabViewController == nil) {
self.routineTabViewController =[[RoutineListViewController alloc] initWithNibName:#"RoutineListViewController" bundle:nil];
[self.view insertSubview:routineTabViewController.view belowSubview:mainTabBar];
routineTabViewController = nil;
[routineTabViewController release];
}
break;
case 2:
if (calendarTabViewController == nil) {
self.calendarTabViewController =[[CalendarTabViewController alloc] initWithNibName:#"CalendarTabViewController" bundle:nil];
[self.view insertSubview:calendarTabViewController.view belowSubview:mainTabBar];
calendarTabViewController = nil;
[calendarTabViewController release];
}
break;
case 3:
if (editTabViewController == nil) {
self.editTabViewController =[[EditTabViewController alloc] initWithNibName:#"EditTabViewController" bundle:nil];
[self.view insertSubview:editTabViewController.view belowSubview:mainTabBar];
editTabViewController = nil;
[editTabViewController release];
}
break;
default:
break;
}
}
And when I implement a button to go to some other page, the tab bar keeps showing. Here is the button implementation in EditTabViewController.m file.
- (IBAction)goToHome:(id)sender {
homeBtn = [[MainMenuViewController alloc] initWithNibName:#"MainMenuViewController" bundle:nil];
[self.view addSubview:homeBtn.view];
}
Per Apple's rules, a TabBarController is supposed to be the main container. Plus, if you just implement a custom UITabBar, are you using that to push the user into other views? If so, if the UITabBar disappears, how does the user ever return?
If you only want the bar visible when a particular page is visible, why not implement a UINavigationController (as the main container) and have the root UIViewController implement a UIToolbar that performs the same functions. Then, when you navigate to another page (I'm assuming here that you mean a new screen, not a different page in a UIPageControl or a web page in a UIWebView), you push in a new UIViewController that doesn't contain the UIToolbar.
Kind of like this:
--UINavigationController
|
-->UIViewController as RootViewController --> Contains UIToolbar
|
-->Pushes UIViewController --> Has no UIToolbar
Edit/Update
I just saw your code, and I'm not sure I understand what you're trying to achieve. I think you might be trying to somehow implement behavior similar to a UINavigationController without actually using one.
Edit/Update #2
I think you are wanting behavior that can be implemented like this:
UINavigationController (containing IconMenuViewController as RootViewController)
|
--> PageViewController (push into this from any icon touch in IconMenuViewController)
--> Contains UIToolbar/UITabBar
If you use the hierarchy above, the UINavigationController will automatically provide you with the NavigationBar at the top of the screen and give you a back button. As long as you make the UIToolbar or UITabBar part of the PageViewController, it should appear and disappear with its view controller as you push and pop it. Does that make sense?

Advice with Tab Bar and Nav Bar

I'd just like to clear something up..
I have an app where the Main Window UI has a Tab bar with 3 tabs (opt1, opt2, op3). Each opt has its own xib file where i've drawn their own interfaces.
In my app delegate class I have included a UITabBar *rootController, and hooked this up to my tab bar in my Main Window xib file.
Now.. In the Tab bar, I have dragged in 3 navigation controllers (1 for each opt) and inside each one I have a 1) tab bar icon, 2) navigation bar and 3) view controller.
Back in my app delegate.h class I have included code for UINavigationController *nav1, nav2, nav3..and hooked these up accordingly in IB in MainWindow.xib (TabBar->navController1, navController2, navController3).
Is this the right way to do it? Also how can I make use of these nab bars in my opt1, opt2, opt3 class files?
here is my code:
app delegate.h
#import <UIKit/UIKit.h>
#class LoginViewController;
#interface myAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
UINavigationController *navigationController1, *navigationController2, *navigationController3;
IBOutlet UITabBarController *rootController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController1, *navigationController2, *navigationController3;
#property (nonatomic, retain) IBOutlet UITabBarController *rootController;
#end
appdelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:[rootController view]];
[window makeKeyAndVisible];
LoginViewController *loginViewController = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil];
[self.rootController presentModalViewController:loginViewController animated:NO];
}
Then in my LoginController.m class , when the user enters correct credentials I call
[self dismissModalViewControllerAnimated:YES];
In my MainWindow.xib, I hook up my rootController to a TabBarController. In the TabBarController I have put 3 NavigationControllers inside it and linked them to 3 tabOption classes which each have their own .xib view.
The tab bar switches between the 3 option views nicely. However in 1 .xib view I have a button to open a new .xib. So in my tabOption1 class I have the following:
-(IBAction)openBook:(id)sender{
UIViewController *nextVC = [[PageViewController alloc] initWithNibName:#"PageView" bundle:nil];
[self.navigationController pushViewController:nextVC animated:YES];
}
However this does not open up my PageView.xib... I have connected it to my PageViewController class and everything too..and the button works because I've tested it with a UIDialog
Have you seen the Apple Programming Guides? They might give you a better understanding of how everything ties together - you could start here:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/NavigationControllers/NavigationControllers.html#//apple_ref/doc/uid/TP40007457-CH103-SW1
In answer to your question, that looks like an OK way of setting up. I really would recommend reading up a bit though :)
In response to your comment, that looks like a reasonable way to do what you're trying to achieve. If it works, then it works.
In response to your other issue then you can get the navigation controller object by doing this: self.navigationController
So you can "go to" a new view controller like this:
// make the view controller
UIViewController *nextVC = [[MyCustomViewController alloc] initWithNibName:#"MyCustomViewController" bundle:nil];
// push it onto the navigation stack
[self.navigationController pushViewController:nextVC animated:YES];
To add this to the click event on a button you need to create the button in interface builder and create an IBAction in your code. The IBAction might look like this:
- (IBAction)pushNextViewController:(id)sender {
UIViewController *nextVC = [[MyCustomViewController alloc] initWithNibName:#"MyCustomViewController" bundle:nil];
[self.navigationController pushViewController:nextVC animated:YES];
}
Then you need to link to it from interface builder. I'm not sure how to do this, I generally don't use interface builder, and certainly haven't used it since about XCode 3.
To do it programatically you can use this method:
[MyButton addTarget:self selector:#selector(pushNextViewController:) forControlEvents:UIControlEventTouchUpInside]; // always use touch up inside
Keywords to look up to help you find tutorials and stuff on the internet: ibaction uinavigationcontroller pushviewcontroller:animated: popviewcontrolleranimated:

How do you add a UITabBarController to an existing project

I have an iPhone project that starts out with a standard UIView based Window... when the user clicks a button its suppose to launch into a new view with a UITabBarController -- similar to the way the iTunes Connect app behaves after you login. There are no sample code examples in the Apple documentation doing what I want but I know its possible because Apple has done it in their own apps (another example is the MobileMe iDisk app for iPhone).
I already tried the standard -presentModalViewController:animated: method and that did not work because there isn't a view that I can attach within the UITabBarController.
Next I am going to attempt to work with two window XIBs within the App Delegate to see if I can get that approach to work instead.
I would appreciate any insight if you know how to answer this little problem of mine. =)
What I ended up doing is this:
In my App Delegate, I have the following in my interface:
#interface myAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow * window;
LauncherViewController * startup;
UITabBarController * tabs;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet LauncherViewController * startup;
#property (nonatomic, retain) IBOutlet UITabBarController * tabs;
#end
In my implementation file, I add the following to the app start up function:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[self.window addSubview:self.startup.view];
[self.window makeKeyAndVisible];
NSNotificationCenter * notifier = [NSNotificationCenter defaultCenter];
[notifier addObserver:self
selector:#selector(launch)
name:MyAppLoginInitializedNotification
object:nil];
[notifier addObserver:self
selector:#selector(logout)
name:MyAppLogoutNotification
object:nil];
return YES;
}
- (void) launch {
[self.startup.view removeFromSuperview];
[self.window addSubview:tabs.view];
[self.window makeKeyWindow];
}
- (void) logout {
[self.tabs.view removeFromSuperview];
[self.window addSubview:startup.view];
[self.window makeKeyWindow];
}
My main XIB contains both the standard UIViewController defined as LauncherViewController as well as a generic UITabBarController. As soon as my main launcher controller authentices the user credentials and sends the MyAppLoginInitializedNotification, the app delegate switches from the launcher to the tab view enabling me to continue on with my app logic.
UITabBarController really is just a subclass of UIViewController, so -presentModalViewController:animated: should work:
UITabBarController *someController = [[UITabBarController alloc] init];
someController.viewControllers = /* your View Controllers here */
[self presentModalViewController:someController animated:NO];
if i understand your issue correctly, you want to start the UITabBarController View after the first view you mentioned in your Question, i am attaching a link doing the same thing you need except you have an Extra view before the UITabBarController View appears, hope it will give you a guide.
http://www.mobisoftinfotech.com/blog/iphone/iphone-tabbar-uitabbarcontroller-tutorial/
I don't think you have to re-add the UITabBarController in the nib file. Just create it in code, add it as the poster above says, and you should be good to go. Here's some code that works for me.
UITabBarController *nextController = [[UITabBarController alloc] init];
FirstController *firstView = [[FirstController alloc] initWithNibName:#"FirstView" bundle:nil];
SecondController *secondView = [[SecondController alloc] initWithNibName:#"SecondView" bundle:nil];
ThirdController *thirdView = [[ThirdController alloc] initWithNibName:#"ThirdView" bundle:nil];
[nextController setViewControllers:[NSArray arrayWithObjects:firstView, secondView, thirdView, nil] animated:NO];
Till this point it should be the same, but I'm pushing a tabbar controller into the uinavgiationcontroller instead, so this is where we might differ. I do it as follows:
[self.navigationController pushViewController:nextController animated:YES];

Persistant view anywhere in the app

I'm pretty new to Objective-C and I'm working on a webradio app.
My app is composed of some NavigationControllers included in a TabBarController.
I want to make a View wich would stay just above the TabBar ALL THE TIME. (it will contain the audio player controls and must be accessible anywhere in the app)
What would be the best way to do so?
Thanks!
SQ;p
You need to add your view as a subview of the UITabBarController view property:
m_yourToolbar =[[UIToolbar alloc] initWithFrame:CGRectMake(0, 401, 320, 44)];
// set some properties on the toolbar
// ...
[self.tabBarController.view m_yourToolbar];
This adds the UILabel blah over the content for every tab in the UITabBarController (m_tabBarController).
#interface YouAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIToolbar * m_yourToolbar;
// ... whatever other stuff you have in your app delegate
}
#property (nonatomic, retain) UIToolbar * yourToolbar;
In your app delegate implementation you will need:
#synthesize yourToolbar= m_yourToolbar;
// .. other app delegate stuff
So in your view controllers that need to update the toolbar, you can get hold of the app delegate, grab the yourToolbar property and set attributes on it:
AppDelegate *appDelegate = (YouAppDelegate *)[[UIApplication sharedApplication] delegate];
// set stuff on the toolbar property
appDelegate.yourToolbar.stuff = stuff;

iphone switchview with buttons,how to allow press button one time only?

im newbie developer and creating my first iphone app... and i have one little problem :)
i switching in my program 2 views, secondView is over firstView, and when i press 2 times or more on button to show the SecondView iphone simulator stopping worling and if after i press to show the FirstView he still showing SecondView view :(...
and i need help how to make button to pressing one time only, and if after switch back to FirstView to can again press one time,and shows like presse,now it show pressed only when i tuch it,... i want like buttons in TabBar, and if i use the TabBar is more harder for me i dont know how to resize it to height and add custom background, and change the effect of pushed button
Thanks you very much and sorry for my bad english!.
here is what code i use to switching views with buttons
// FirstView.h
#import <UIKit/UIKit.h>
#interface FirstView : UIViewController {
}
-(IBAction) goToSecondView:(id) sender;
-(IBAction) goToFirstView:(id) sender;
#end
// FirstView.m
#import "FirstView.h"
#import "SecondView.h"
#implementation FirstView
SecondView *secondView;
-(IBAction) goToSecondView:(id) sender{
secondView = [[SecondView alloc] initWithNibName:#"SecondView" bundle:nil];
[self.view addSubview:secondView.view];
}
-(IBAction) goToFirstView:(id) sender {
[secondView.view removeFromSuperview];
}
thank you very much!
This:
#implementation FirstView
SecondView *secondView;
... is most likely the source of your crash. You shouldn't define instance variables in the implementation. The compiler may allow it but the runtime will be confused and the instance variable will not be properly retained.
You should define it like:
#interface FirstView : UIViewController {
SecondView *secondView;
}
#property(nonatomic, retain) SecondView *secondView;
...and use it like:
-(IBAction) goToSecondView:(id) sender{
UIView *newView = [[SecondView alloc] initWithNibName:#"SecondView" bundle:nil];
self.secondView=newView;
[newView release];
[self.view addSubview:self.secondView.view];
}
For clarity you should also rename FirstView and SecondView to FirstViewController and SecondViewController because they are view controllers and not views themselves.
More generally, what you are trying to do is dangerous and difficult. You don't swap views by adding and removing them as subviews. You need to swap out view controller and their views using a UINavigationController or a UITabbarController. In Xcode File>New Project, there is a Navigation based project and a Tabbar based project templates. Either will provide you most of the code you need to implement a simple app using either controller.
It will be well worth your time to spend a day learning how to use these controllers properly. With your current design, your app will break if it gets much more than two views.