UIToolbar and other views - iphone

I know how to add a UIToolbar, which I'm doing in rootviewcontroller.m:
[self.navigationController.view addSubview:toolbar];
However, when I navigate to other views, the toolbar stays up, which is ok, but how do I access it to hide/show it?
Inside rootviewcontroller I would use this:
toolbar.hidden = NO;
But I can't seem to find a way to do this outside of rootviewcontroller.m
Can you please show me an example of hiding it from another class?

There are two options;
1) Add a property to your controller so external classes can access to the toolbar object.
2) Add a function to your root view controller that can be used to toddle the toolbar.
I would recommend #2 since it restricts what external classes can do.
E.g.
-(void) hideToolbar:(BOOL)hidden
{
toolbar.hidden = hidden;
}

The problem is that you shouldn't be adding it to self.navigationController.view; you should be adding it to self.view. Correcting that should fix it for you.

You could try adding the following line during the initialisation of the View Controllers for which you don't want the bar to appear.
[self.navigationController setToolbarHidden:YES animated:NO];
F.

Andrew Grant's answer is what you're looking for. However, you should rename the method to
-(void) isToolbarHidden:(BOOL)hidden {
toolbar.hidden = hidden;
}
It makes more sense that way when looking at the code.

Related

Overwriting UINavigationBar to set a default titleView

What I want to do is a navigation bar with a image on it. I have a tab controller on my main view, and inside each tab I have a UINavigationController. From inside the UIViewController that my tab/navigationController calls, I could set the titleView without much problem, doing this inside the viewDidLoad method:
self.navigationItem.titleView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"mylogo.png"]] autorelease];
But, I want to replace all titles in my navigationBar for this view, and it seems ugly to repeat this everywhere. So I did this on the delegate (after linking all the Outlet stuff)
self.tabOneNavController.navigationBar.topItem.titleView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"mylogo.png"]] autorelease];
Again, it worked! ok, I'm almost getting there.
But the point is, I've 5 tabs and all of them have navigationControllers inside. I reduced the code repetition from every internal view to only 5 times, but it still. It requires that I do that for the NavController of each tab.
Then I tried to extend the UINavigationBar to create my own, where I could set this in the initializer, and use it in the interface builder as the object class. But it doesn't seem to work. Here is what I did:
#implementation MyNavigationBar
- (id)init {
self = [super self];
self.tintColor = [UIColor greenColor];
self.topItem.title = #"testing please work";
return self;
}
#end
in the interface file MyNavigationBar inherits from UINavigationBar. But this didn't work. Should I overwrite other method? which one? is this a good practice?
I'm not even sure if I should add one navigationBar for each tab, as I said, I have tabs and I want to have a navigation bar / navigate inside them. By now, after a near death experience trying to figure out how the interface builder / outlets and classes work, the code is working, I just would like to make unglify it.
Thank you!
The problem of repeating code which you describe has an elegant solution. Objective-C supports something called a "category", which allows you to add methods to a class. A common use for this is to customize navigation and tab bars. In Xcode 4, you would do something like this to add a category on UINavigationBar:
Hit Command+N or open the "New File" dialog. Next, choose "Objective-C category" from the Cocoa Touch menu:
Click Next and you will be prompted to enter the name of the class that you would like to add methods to as a category. It should look something like this:
Then, you should end up with a save file dialog. A quick note about convention here. Convention is to name a category after the original class, the plus sign, and then a description of what you're adding. Here's what yours might look like:
Once you save your file, you will need get something like this:
Look at that beauty. You can now override the default drawing/init methods as well as extend the functionality of the navbar.
I'd suggest looking into the init and drawRect methods, although I don't remember which ones people use. Also, please note that while under NDA, this may change in iOS 5, so just be prepared for that possibility.
Why not define a UIViewController subclass which sets the title view via self.navigationItem.titleView and have your other view controllers extend from that class? Then you're sharing that behavior across all of your controllers without repeating the implementation.

uiview in navigation

I am working with a navigation application. I have a homeViewController with two views(accept, service). When I click on a button in serviceView it should go to acceptView. I should have back button in navigation bar which takes me be back to serviceView from acceptView. When I am trying to use [self navigationController pushViewController, it only accepts viewcontroller but not view. Can any one please tell the alternative. Please help me.
Thanks in advance
You should have a different viewController for each view if you wish to use a navigationController properly.
Set up AcceptViewController and ServiceViewController separately. Then, from the AcceptViewController, you can create a ServiceViewController and push it onto the stack as follows:
-(void)showServiceView {
ServiceViewController *serviceViewController = [[ServiceViewController alloc] init];
[self.navigationController pushViewController:serviceViewController];
[serviceViewController release];
}
Assuming you've references to both acceptView and serviceView, you can just make this work by removing one as the subview and adding the other one as the subview of homeViewController's view. Something like,
[serviceView removeFromSuperview];
[self.view addSubview:acceptView];
for moving to acceptView. Switch them if you want to come back. However this mechanism will be abrupt. Use UIView's transitionFromView:toView:duration:options:completion: method to animate the transition. Something like,
[UIView transitionFromView:serviceView
toView:acceptView
duration:0.5f
options:UIViewAnimationOptionTransitionFlipFromLeft| UIViewAnimationOptionCurveEaseInOut
completion:NULL];
This will remove serviceView and add acceptView as the subview along with a transition to go by.

xCode - Changing views between 2 existing xib-files

I'm very new to xCode and objective-C so I wanted to make a simple textRPG.
I'm currently making a character creation process consisting of 4 xib-files. The only way I got switching views to work was to look at the utility-template. Problem is, now I have the first screen being the delegate for the second screen, being the delegate for the third screen etc. So by the end of the character creation process I can't dismiss the views because that just "steps back" through the views.
When I've searched around for a solution I've found a addSubview-method but it seems like that makes a new view, like, empty to arrange programmatically.
All I need is a simple way to switch from one loaded xib to another xib. Have I misunderstood addSubview or do I need something completely different?
(If it helps: I've worked with VB for several years, in case you notice that I missed some kind of concept concerning views and such)
Thanks in advance! :)
Use this code. It is really simple and works well.
View *view = [[View alloc] initWithNibName:#"xibNameGoesHere" bundle:nil];
view.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:view animated:YES completion:nil];
This will switch to another xib file and the two views won't own one another. I am using it in my own game right now.
#Joakim Ok, this is the way I do it. I have a class called RootViewController : UIViewContoller, whose view I add directly to the window. Then I make a subclass of UIView i.e. MyView. All of my views then subclass MyView. I also make an enum for all my views. In RootViewController you should have a switchView:(int)view method that looks something like this:
-(void) switchView:(myView) view
{
[_currentView removeFromSuperview];
switch(view)
{
case titleView:
_currentView = [[TitleView alloc] initWithRoot:self];
break;
case homeView:
_currentView = [[HomeView alloc] initWithRoot:self];
break;
default: break;
}
[self.view addSubview:_currentView];
[_currentView release];
}
in #interface RootViewContoller define MyView *_currentView;
TitleView and HomeView both subclass MyView and have a common method -(id)initWithRoot:(RootViewController*) rvc.
To switch between views use [_rvc switchView:homeView];
Hope this helps :)
It is called UINavigationController. Idea is
1) You push corresponding 'next' controller into navigation controller each time user submits current screen. Bonus - you'll get 'back' button for free on each step of character creation.
2) After character is created you pop all character creation controllers from stack.
Please read View Controller Programming Guide for iOS before trying to 'switch views' and such. You'll save tons of time and nerves.
another idea is not to use interface builder at all. i have been working with iphone apps for two years now and found that interface builder really prolongs the time to actually make something. make your own root controller and think about the logic you need to navigate through the views.

Same WebView on every view

Basically i have a WebView on SecondViewController and I wish for the WebView to be visible on every view like a tab bar and fully controllable on each view.
Please note the WebView will be on a webpage with a online slideshow so I cannot simply reload on each view
Also in the SecondViewController I have
- (void)webViewDidFinishLoad:(UIWebView *)YouTubePlayer {
I would suggest adding the webView on you window after the you add the tabbarcontroller.view just like:
[window addSubview:tabbarController.view];
[window addSubview:webview];
[window makeKeyAndVisible];
and initially make don't make it visible. You should handle all the webview related methods in the app delegate. Now whenever you don't need it you can hide it by calling the methods your wrote in app delegate from your view controllers.
Hope this helps.
I'd just set up a singleton UIWebView and add it to each view-controller-view when that view controller is about to become visible. Here's one way to do it:
//.h
#interface SharedWebView : UIWebView
{
}
+ (SharedWebView*) shared;
#end
//.m
SharedWebView* g_sharedWebView;
#implementation SharedWebView
+ (SharedWebView*) shared
{
if ( g_sharedWebView == nil )
{
g_sharedWebView = [[SharedWebView alloc] init];
// ... any other intialization you want to do
}
return g_sharedWebView;
}
#end
// in your view controller(s)
#property (readonly) UIWebView* webView
- (UIWebView*) webView
{
return [SharedWebView shared];
}
- (void) viewWillAppear: (BOOL) animated
{
[super viewWillAppear: animated];
[self.view addSubview: self.webView ];
self.webView.frame = CGRectMake(10, 10, 300, 300);
// want to re-set the delegate?
// self.webView.delegate = self;
}
The simplest approach is to just make all of your view controllers aware of this extra view (make the view available through a singleton PinnedViewController or whatever). During each view controller's -viewWillAppear, just do this:
[self addSubview:[[PinnedViewController sharedController] view]];
This will move the view to whoever is currently active (making a view your subview automatically removes you from your old hierarchy).
If that is cumbersome or otherwise unworkable, there are two other options. First, you can subclass UITabViewController (I assume that's what you're using here from your question), and inject your extra view (resizing the content view to make room). This is undocumented and unsupported, so take heed. But it's not incredibly difficult if you don't do too many other fancy tricks.
The other tricky solution is to create a second UIWindow that you float over the main UIWindow (or resize the main UIWindow to make room for it). This is only semi-documented and is also not really supported. But this approach can work if you're trying to put the extra view below the tabbar for instance.
But if your system is simple enough, I recommend just letting your view controllers all manage the pinned view manually. You'll save a lot of code spelunking that way, and you won't have to rely on any undocumented internal view hierarchies.
Sounds like you try to put views on top of this view but not modal. There was this blog entry I once saw that described how you would do something like this. I think it should apply also for your case: semi-modal-transparent-dialogs-on-the-iphone
In iOS UIViewControllers are expected to manage an entire "screen" worth of content so it's not normal to try to share a single view across many view controllers. Trying to have UIViewControllers whose views only manage part of their window is problematic and will result in unexpected behavior as UIKit will not send messages like -viewWillAppear to all view controllers with visible views. Instead you would normally create a single UIViewController whose view includes that web view and whatever other views compose your tab like interface.
Alternately you could have a hierarchy of many view controllers and add a single web view as a subview of all of them. You would then pull your web view delegate behavior out into some non-UIViewController controller class to manage the behavior of the web view.
You can have all your views take up a portion of the screen and have your UIWebView take up the rest. The logic for switching between the other views should remain the same.
For example, in your viewDidLoad method for your UIViewControllers, you could have something like:
self.view.frame = CGRectMake(0, 100, 320, 380);
And in your (say) AppDelegate, you would have your normal call to show the main UIViewController (in your case, it sounds like a UITabBarController?) and also have a call to add the UIWebView. Say, something like:
myWebView.view.frame = CGRectMake(0, 0, 320, 100);
The view controllers and UIWebView would be independent of each other.
You see this pattern, I believe, with apps that have iAds. I've done something just like this with one of my free apps.
Hope this helps!
I got the same effect by simply adding it to the navigationController itself(if you don't have one then just add it).
works great for me in one of my apps.
Could you not use two webviews on your application and simply change the uppermost webview with your more dynamic content?

REALLY simple question about UIViews

I am working on an app that has several different views, two of the which are DetailViewController.h&.m and AddViewController.h&.m. Neither of these particular view have IB xib files associated with them, they just have programmatically generated UITableViews. These views essentially are the same, the only difference, is that in the AddViewController, you put info into cells, and in the DetailViewController that same info is viewable and editable. Essentially the viewDidLoad for the AddViewController overrides the DetailViewController viewDidLoad with different navigation bar items and title. MY QUESTION: Outside of IB, how do I reference which view I am in? I want to have some switches and buttons available in the DetailView, that I don't want available in the AddView. But being that as it is, they are refferencing the same info, and currently just changing the navigation bar items, they aren't seperate like I would like them to be. Inside the DetailView viewDidLoad I'm thinking I need something where its like
if(currentView = DetailView) {
self.view addSubview: onOffSwitch;
}
else onOffSwitch. hidden = YES;
Or something to that effect. Obviously if the above code actually worked, I wouldn't be writing this question :) Its probably just a syntax issue I can't hammer out, if you could please help me out, it would be greatly appreciated! Thanks
Well there is similar question here
But for your case you can do it like:
if([[self class] isKindOfClass:[DetailViewController class]]) {
self.view addSubview: onOffSwitch;
}
else
onOffSwitch. hidden = YES;