I have a problem with switching views in an iPhone application.
I have the source code of "Beginning iPhone 3 Development" (http://books.google.com/books?id=TcP2bgESYfgC&printsec=frontcover&dq=beginning+iphone+3+development#v=onepage&q=beginning%20iphone%203%20development&f=false) - chapter 6 - Multiview Applications.
Now I have the problem, I want to create a new view which should switch by clicking the button on the blue screen "Press me". But it did not work.
I add the these lines to the IBAction that the button on the blue screen is pressed:
StartViewController *startController = [[StartViewController alloc] initWithNibName:#"StartViewController" bundle:nil];
self.startViewController = startController;
[self.view insertSubview:startController.view atIndex:1];
[startController release];
But the toolbar at the bottom won't disappear. But I want that this toolbar disappear.
If I wrote
[self.view insertSubview:startController.view atIndex:0];
instead of
[self.view insertSubview:startController.view atIndex:1];
the new xib lies behind the old one, so I see both views, the old and the new.
Why? I do not understand this.
Thanks a lot in advance & Best Regards Tim
The toolbar is in the SwitchView so you would need to hide it from the view if you want it to hide. You could make an IBOutlet for the toolbar and then call setHidden:(BOOL) to hide it. You will need to do this from BlueViewController so you will need a way to get to your super view (which is SwitchView). You will also need to remove the BlueView from the super view by calling removeFromSuperView on blueViewController before inserting the new view into place. It is basically the same code that comes from the switch button in SwitchViewController.
Update:
I looked at your code. In BlueViewController.m use this for blueButtonPressed:(id)sender
StartViewController *start = [[StartViewController alloc] initWithNibName:#"StartViewController" bundle:nil];
self.startViewController = start;
[start release];
View_SwitcherAppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
SwitchViewController *switchController = appDelegate.switchViewController;
switchController.theToolbar.hidden = YES;
[self.view removeFromSuperview];
[self.view insertSubview:startViewController.view atIndex:0];
You will also need to add these two imports for "View_SwitcherAppDelegate.h" and "SwitchViewController.h".
Related
I have a problem with the display of my popover. After initWithContentViewController: and presentPopoverFromBarButtonItem:permittedArrowDirections:animated: it cuts corners of the navigation bar. How should I fix it?? Thanks.
This is the code I'm using
NavContr *nav = [NavContr new];
nav.navigationBar.backgroundColor = [UIColor redColor];
UIPopoverController *tempPop = [[UIPopoverController alloc] initWithContentViewController:nav];
[tempPop presentPopoverFromBarButtonItem:mainButtonItem permittedArrowDirections:UIPopoverArrowDirectionUp animated:NO];
EDIT: I have resolved this problem:
+ (void)configure:(UINavigationController *)navController {
UINavigationBar *navigationBar = navController.navigationBar;
UIView *contentView = nil;
for (UIView *view in navController.view.subviews) {
if ([[NSString stringWithFormat:#"%#", [view class]] isEqualToString:#"UILayoutContainerView"])
contentView = view;
}
// setting frame to navigation bar and content view
[navigationBar setFrame:CGRectMake(navigationBar.frame.origin.x, 0, navigationBar.frame.size.width, navigationBar.frame.size.height)];
[contentView setFrame:CGRectMake(contentView.frame.origin.x, 0, contentView.frame.size.width, contentView.frame.size.height + navigationBar.frame.size.height)];
[navController.view bringSubviewToFront:contentView];
for (UIView *customView in contentView.subviews)
customView.frame = CGRectMake(customView.frame.origin.x, customView.frame.origin.y + navigationBar.frame.size.height, customView.frame.size.width, customView.frame.size.height);
[contentView addSubview:navigationBar];
[contentView bringSubviewToFront:navigationBar];
}
This is probably because you have no root view controller, or are otherwise fiddling with the navigation controller in ways it was not meant to be played with. This is how you ought to be setting up the popover:
MyCustomViewController *viewController = [[UIViewController alloc] initWithNibName:#"MyCustomViewController" bundle:nil]; //or storyboard or whatever
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:viewController]; //you should have a root view controller before displaying the popover
tintColor = [UIColor redColor];
UIPopoverController *tempPop = [[UIPopoverController alloc] initWithContentViewController:nav];
[tempPop presentPopoverFromBarButtonItem:mainButtonItem permittedArrowDirections:UIPopoverArrowDirectionUp animated:NO];
There are a few very important things going on here:
Your navigation controller should have a root view controller before you display it.
This code is using a standard UINavigationController instance. According to the documentation, you should not subclass UINavigationController, nor should you try and reinvent the wheel. Apple has created a complex and comprehensive framework, UIKit, that you can use to build amazing apps. If you try and step outside the box, you'll be creating an awful lot of work for yourself without any appreciable benefit.
This is using the tintColor property of the UINavigationBar class. If the tint is insufficient for your UI, you can also set the background image manually (refer to the docs).
If you want to make a popover with a navigation controller, use the built-in UINavigationController class. Don't subclass it and don't reinvent it. To customize the appearance of the navigationBar, use the UI_APPEARANCE_SELECTOR methods in the UINavigationBar class.
I get the solution before add CALayer the UIPopOverController shows like
after adding below lines in table view class i get the following UIPopOverController
#import <QuartzCore/QuartzCore.h>
CALayer *imageLayer2 = self.tableView.layer;
[imageLayer2 setCornerRadius:-20];
[imageLayer2 setBorderWidth:1];
Try it in your project may be it works!!
Thanx
I have tried & replicate the issue you are facing, made some R&D. It's due to the line of code below :
nav.navigationBar.backgroundColor = [UIColor redColor];
While you set the background color of the navigation bar it will behave weird due the native shape of the pop up. Try and remove the below line, you will definitely have issue resolved.
If you are specifying the Rect where the popover appears, we've found that using decimals can result in weird distortions like that. Be sure you're using whole number for origin and size.
So i wanted to build a tabbar that has more than 5 items and is scrollable and found this article.
Easy done by subclassing the UITabBarController and hide the existing tabbar:
for(UIView *view in self.view.subviews)
{
if([view isKindOfClass:[UITabBar class]])
{
view.hidden = YES;
break;
}
}
Then i just add a UIScrollView and throw some buttons in there based on the items-collection of the tabbarcontroller.
int i = 0;
for (UITabBarItem *item in self.tabBar.items)
{
UIView *tab = [[[UIView alloc] initWithFrame:CGRectMake(i*60, 0, 60, 60)] autorelease];
UIButton *btn = [[[UIButton alloc] initWithFrame:CGRectMake(7.5, 1, 45, 45)] autorelease];
[btn setImage:item.image forState:UIControlStateNormal];
btn.tag = i;
[btn addTarget:self action:#selector(didSelectTabrBarItem:) forControlEvents:UIControlEventTouchUpInside];
[tab addSubview:btn];
[self.scrollView addSubview:tab];
i++;
if(self.selectedViewController == nil)
[self setSelectedIndex:0];
}
I am overriding the setSelectedindex/ViewController since i need some addition drawing.
-(void)setSelectedViewController:(UIViewController *)selectedViewController
{
[super setSelectedViewController:selectedViewController];
[self startTimer];
}
-(void)setSelectedIndex:(NSUInteger)selectedIndex
{
[super setSelectedIndex:selectedIndex];
[self startTimer];
}
The problem is that when I am pressing button number 5, 6 or 7, the tabbarcontroller opens the More view. How do i get rid of that and make the last three items act like the other ones? - Could it be the call to the super?
My guess would be to completely kill the UITabBarController and implement my own custom tabbar. But is it possible to disable the more menu and have the UITabBarController select item 5, 6 and 7 as normal?
So, since I'm too lousy to write a completely new tab bar i decided to investigate and try to hack UITabBarController.
And here's the solution:
The actual problem is that when you touch a tab bar item with index above 4, the UITabBarController vil actually display the moreNavigationController. This is a UINavigationController containing a view of type UIMoreViewControllerList, which is a type from the private Cocoa framework together with an instance of the ViewController you selected.
So how do we get rid of the More button?
Simply remove the UIMoreViewControllerList from the moreNavigationController collection, leaving only the ViewController you selected.
-(void)setSelectedViewController:(UIViewController *)selectedViewController
{
[super setSelectedViewController:selectedViewController];
if([self.moreNavigationController.viewControllers count] > 1)
{
//Modify the view stack to remove the More view
self.moreNavigationController.viewControllers = [[[NSArray alloc] initWithObjects:self.moreNavigationController.visibleViewController, nil] autorelease];
}
}
Well that leaves us with a Edit button in the top right corner (Titlebar).
How do you get rid of that, then?
Yeah. Thats another dirty hack. To remove the Edit button I'd actually have to implement one method from the UINavigationControllerDelegate for the moreNavigationController on my custom UITabBarController.
//navigationController delegate
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if ([navigationController isKindOfClass:NSClassFromString(#"UIMoreNavigationController")])
{
// We don't need Edit button in More screen.
UINavigationBar *morenavbar = navigationController.navigationBar;
UINavigationItem *morenavitem = morenavbar.topItem;
morenavitem.rightBarButtonItem = nil;
}
}
And thats the way to kill off the default More functionality. I really think Apple pissed their own pants here creating a UITabBarController that both handles logic and UI stuff.
Why not create a controller that has the logic to preload the ViewControllers and switch between then, and then an implementation you can use if you want the More thingie. - Or even better: Make it possible to disable the More functionality.
This is pretty close, it may help you
https://github.com/iosdeveloper/InfiniTabBar
I should finalize this thread. I have been having the stuff above in a App Store for a year and it has caused massive problems in the long run. It works, but it quirks when you rely on the built in features of UITabbarcontroller as it messes around with the view stack.
After going around this hot ash for over a year we decided to build our own tabbarcontroller/menucontroller. Thta took like a day and have freed us from all the fixes and quirks.
My hack works, but I recommend building your own navigation class - it will pay off in the long run :-)
I had a similar problem and solved it by using a UITabBarController and hiding the tab bar. Then I drew a custom tab bar over the top of it and when a button for a tab was clicked, call
tabbar.selectedIndex = index
Where 'tabbar' is the original UITabBarController. Setting the selectedIndex property of a UITabBarController changes the currently displayed view controller to the controller at that index. This way you still get all the functionality of a UITabBarController but you can have as many tabs as you want and customize it however you want.
Otherwise, I don't think there is a way to remove the "more" functionality.
I am using XCode to develop a Cocoa touch application for the iOS platform but have had trouble finding out how to get a swipe gesture implemented that would allow the user to swipe their finger left or right to change to a new ViewController (nib/xib file). I have done a swapView IBAction using a button and modal transitioning and I have read about Apple's TouchGestureRecognizer but I don't know how to implement a swipe action that would allow a view change.
I do NOT want to use a scroll view, as I have several dozen view controllers, that I want the user to be able to swipe through.
Here is an example:
First View Controller.xib:
SwipeRight- Go to second View Controller.xib
Second View Controller.xib:
SwipeLeft- Go to first View Controller.xib
SwipeRight- Go to third View Controller.xib
etc, etc
I have not used UISwipe/Touch Gestures before but I have used an IBAction method to switch views using a button with Modal Transitioning (see below):
-(IBAction)swapViews; {
SecondViewController *second2 =[[SecondViewController alloc initWithNibName:#"SecondViewController" bundle:nil];
second2.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:second2 animated:YES];
[second2 release];
}
Is using a swipe to do a similar method formatted differently? If so, how do I sort this out and format it.
Thank You
Edit - Answer as Per Comment on Question
Place this in your viewDidLoad
UISwipeGestureRecognizer *swipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeLeftDetected:)];
swipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeRecognizer];
[swipeRecognizer release];
Then add a selector as by pasting the following code into your main...
- (IBAction)swipeLeftDetected:(UIGestureRecognizer *)sender {
NC2ViewController *second2 =[[NC2ViewController alloc] initWithNibName:#"NC2ViewController" bundle:nil];
second2.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:second2 animated:YES];
[second2 release];
}
Then just make sure you import the otherViewController you are swapping to using
#import "SecondViewController"
at the top of your main file. Hope this helps.
End Edit
This sounds like a perfect time to use UIGestureRecognizer or, more specifically, UISwipeGestureRecognizer.
For more info on how to use them, read up in the Gesture Recognizers section of the Event Handling Guide.
Lets assume you want to swipe left to bring up another view from the right.
In the storyboard, drag and drop a swipe gesture recognizer. It will make an icon below the view controller; drag this icon and drop onto the ViewController you want to navigate to. This will add a segue, select custom segue. Then create a UIStoryboardSegue class. Add the following code:
- (void)perform {
UIViewController* source = (UIViewController *)self.sourceViewController;
UIViewController* destination = (UIViewController *)self.destinationViewController;
CGRect sourceFrame = source.view.frame;
sourceFrame.origin.x = -sourceFrame.size.width;
CGRect destFrame = destination.view.frame;
destFrame.origin.x = destination.view.frame.size.width;
destination.view.frame = destFrame;
destFrame.origin.x = 0;
[source.view.superview addSubview:destination.view];
[UIView animateWithDuration:0.5
animations:^{
source.view.frame = sourceFrame;
destination.view.frame = destFrame;
}
completion:^(BOOL finished) {
UIWindow *window = source.view.window;
[window setRootViewController:destination];
}];
}
I have used an actionsheet in my project and when it appears it show all buttons but last (4th) button does not responds to my click(only it's half part responds)..
I know the reason it is because i have used a TabBarController and the present class is inside that tabbar controller....
only that part of the actionsheet is responding which is above the tabs....and my last button is half above and half is on top of tabbar
please help
i suggest using this:
[actionSheet showInView:[UIApplication sharedApplication].keyWindow];
I had the same problem that you have and using this method to show it worked for me. The TabBar wants to stay key Window what makes your bottom button appear above, but is actually under the tabbar.
Hope this does the trick for you..
Edit
If you use landscape mode and the method above doesn't work. You can use the following fix:
#Vinh Tran: [sheet showFromTabBar:self.parentViewController.tabBarController.tabBar]
What method do you use to show your actionsheet. Try showFromTabBar: method
The real problem comes in, when your interface is rotated to landscape and the parent view controller has a transformation on it. Believe me, that's a realistic scenario, doh. Then the action sheet is clipped and you can't use the parentViewController because it is transformed. The solution to avoid all these issues is to create a new window, add a rotatable view controller as rootViewController and use its view to display the sheet.
CGRect applicationRect = [[UIScreen mainScreen] bounds];
UIWindow* actionSheetWindow = [[UIWindow alloc] initWithFrame:applicationRect];
RotationViewController* rootViewController = [[RotationViewController alloc] initWithNibName:nil bundle:nil];
actionSheetWindow.rootViewController = rootViewController;
[rootViewController release];
actionSheetWindow.hidden = NO;
UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle:nil];
[actionSheet setCancelButtonWithTitle:#"Cancel" handler:^{
actionSheetWindow.hidden = YES;
[actionSheetWindow release];
}];
[actionSheet showInView:rootViewController.view];
The code above uses BlocksKit, but you can do it also by using the actionSheet delegate and instance properties.
RotationViewController is just a UIViewController subclass that implements
- (void) viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor];
self.view.opaque = NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
In the iPhone maps app there's a toolbar at the bottom of the map view (it contains the Search/Directions segment control and others). When moving from the map view by clicking on a callout, the toolbar slides out with the map view, leaving the next view (a table controller) with no toolbar.
I've tried to do the same thing with [self.navigationController setToolbarHidden:YES animated:YES] in the second view controller, but this gives a strange toolbar sliding down animation, while the map view is sliding to the left.
Using [self.navigationController setToolbarHidden:YES] in viewDidLoad also causes a bad effect (it makes the toolbar disappear the moment the push animation starts, leaving an ugly white space).
I'm assuming the answer to this is to use a nib file, but I'd prefer to do it programatically (if possible).
How can I get the toolbar to "stick" to the map view and slide out with it when I push a new view controller? Thanks.
Gourmet Haus Staudt http://img.skitch.com/20100518-xfubyriig48d3ckaemjg2ay8q.jpg
It turns out the answer is to create the toolbar directly and add it to the view yourself. This is in the code for a UIViewController with a UINavigationController. The frame coordinates can change according to what is on screen.
- (void)viewDidLoad
{
// Add a toolbar to the view
CGRect toolbarFrame = CGRectMake(0, 372, 320, 44);
UIToolbar *myToolbar = [[UIToolbar alloc] initWithFrame:toolbarFrame];
UIBarButtonItem *compassButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"compass.png"]
style:UIBarButtonItemStyleBordered
target:self
action:#selector(zoomToCurrentLocation)];
compassButton.width = 30.0f; // make the button a square shape
[myToolbar setItems:[NSArray arrayWithObject:compassButton] animated:NO];
[compassButton release];
[self.view addSubview:myToolbar];
[super viewDidLoad];
}
I was around this for a day once. Really dont get the programatically answer, but the best way to views to behave correctly, is to do the interface in the interface builder. If you set items for a toolbar in your code like:
[self.navigationController setToolbarItems: control1, control2,..., nil] animated: NO];
with my little experience, I can say that you are saying to the entire application to have a toolbar present when you push new views unless you hide it (or you are using a tabBar), but hiding it you get those unwanted effects.
You can try this:
[self.navigationController setToolbarHidden:YES animated:YES];
in your first controller - (void)viewWillDisappear:(BOOL)animated method,
and setting hidden to NO in - (void)viewWillAppear:(BOOL)animated method in the first controller too.
Hope this helps.
PS: And if you get the programatically answer, let me know! =P
Override the second view controller's -viewWillAppear: method to hide the toolbar.