Slide the whole screen of your app that uses UITabbarController as rootcontroller - ios

I'm using a tabbarcontroller in my app with several viewcontrollers inside it, just normal standard stuff. Lately I need to add the ability to slide the whole screen when I click a button from my content view.
This is what my appdelegate does:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window.root = self.tabBarController; //tabBarController is IBOutlet to the tabbar
}
And in one of my viewcontroller I do this:
- (IBAction)filterButtonTapped:(id)sender {
[UIView animateWithDuration:0.2 delay:0.0f options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState animations:^{
//slide everything to the right?
self.navigationController.view = CGAffineTransformMakeTranslation(260.0f, 0.0f);
} completion:^(BOOL finished) {
//do something, possibly show the view that comes up from the left
}];
You might ask why does the button needs to be inside the contentview, well because my apps want to be designed that way I guess?
Now, the content of the tab bar does slide but not the tab bar below, I know it's because the self.navigationController.view is for the contentview inside the tab bar.
I've been trying to find a way to slide/animate the whole thing but from inside the contentview is it possible to get to the root?
What's your suggestion to do this?

You can access your tab bar controller view from any VC inside using
self.tabBarController.view
Then just animate that view.

Related

transitionFromView with UIViewAnimationOptions similar like navigating with UINavigationController

I'm using a similar approach described here for the animation from one view controller to another:
UIWindow *window = (UIWindow *)[[UIApplication sharedApplication].windows firstObject];
[UIView transitionFromView:window.rootViewController.view
toView:vc.view
duration:0.65f
options:UIViewAnimationOptionTransitionCrossDissolve // transition animation
completion:^(BOOL finished){
window.rootViewController = vc;
}];
Looking into the UIViewAnimationOptions I didn't found an option for the default animation, which occurs when doing the same with UINavigationController.
Is it possible to get the same animation behavior (moving the view left)? How?
I tried it with this animation:
[UIView animateWithDuration:0.65 animations:^{
view.transform = CGAffineTransformMakeTranslation(-view.frame.size.width, 0);
} completion:^(BOOL finished) {
// do something
}];
but while translating to the new view the background is completely black instead of bringing the other view controller in.
Now I'm doing it in a different way. I start with my navigation controller and its root view. Then I push another view controller on the stack. In viewDidAppear of this new view controller I'm removing the first view controller from the navigation stack. One downside: You can see the back button for a short time.
The animation solution I tried will need the other view controller animated in. Also I had problems with views which very not layout correctly (because of edgesForExtendedLayout).

How do I draw main view underneath my UINavigationBar so when the bar shows/hides, the view is unaffected?

Here's the situation:
I am making an app for iPad w/ iOS 6 using Autolayout along with UINavigationController. What I am trying to do is:
Segue from one view controller to the next with a standard push segue.
When I arrive at the new view controller, hide the nav bar with animation.
As the nav bar hides, I want my view to not shift at all. In fact, I want my view to effectively be drawn underneath the nav bar from the beginning, so I'm left with no shifting or movement of content and no black bars. For reference, this is what happens in the Amazon Kindle app when you go into a book.
With my current code, the contents of my view shift up to fill in the void left by the UINavigationBar.
I've tried force-setting the frame of my UIViewController's view and my UINavigationController's view to the entire iPad screen in the viewWillAppear method of my viewcontroller but no dice. I've experimented w/ Constraints in Autolayout but that also didn't get me to where I wanted to go.
Any help you can give would be great!
Try following before animating the navigation bar:
self.navigationController.navigationBar.alpha = 0.99f;
I didn't try this but this should work.
Looks like you need to add custom navigation bar in your new view and animate it to disappear.
I think, hiding original Navigation bar of Navigation Controller without shifting the view is not possible.
Rather add UINavigationBar to xib file, bind it to IBOutlet uiNavigationBar and try following code
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:NO];
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect f = self.uiNavigationBar.frame;
f.origin = CGPointMake(f.origin.x, f.origin.y - 44);
self.uiNavigationBar.frame = f;
} completion:^(BOOL finished) {
NSLog(#"done");
}];
}

Is it correct to move the navigation bar frame?

I have a navigation bar based ipad app.
At some point I want to push another view controller into the views controller hierarchy. Then, when the users tabs some button I want to show a leftMenu controller. To do so I have two views:
A content view which has all the content
And a not visible view which is the leftMenu. This one is under the content view.
So when the user presses the button, what Im doing right now is moving the content view and the navigation bar to the right to make the leftMenu visible:
self.navigationController.navigationBar.frame = CGRectMake(271.0, self.navigationController.navigationBar.frame.origin.y, self.navigationController.navigationBar.frame.size.width, self.self.navigationController.navigationBar.frame.size.height);
self.contentView.frame = CGRectMake(271.0, self.contentView.frame.origin.y, self.contentView.frame.size.width, self.contentView.frame.size.height);
This is working, but the first row in the left menu is not "clickable" where the nav bar is supossed to be. Its like the navigation bar is still there capturing the tab events.
Is it correct to do?:
self.navigationController.navigationBar.frame = CGRectMake(271.0, self.navigationController.navigationBar.frame.origin.y, self.navigationController.navigationBar.frame.size.width, self.self.navigationController.navigationBar.frame.size.height);
If not, whats the propper way to achieve what I want?
Heres and image ilustrating what the problem is:
I think it's best to use a custom container controller to do this kind of thing, rather than moving a navigation bar. In IB, this can be set up quite easily. Start with a UIViewController, add a container view to it, and size how you want. Then in the inspector, set its x value to minus its width, which will put it off screen to the left. Then add another container view and size it to be full screen. You can then delete the view controller that you got with that container view, and right drag from the container view to your initial navigation controller (of your already setup UI) to connect it up with an embed segue. The UIViewController that you started with should be made the initial view controller of the storyboard. To move in the side view, I use this code in that custom container controller:
-(void)slideInLeft {
if (isRevealed == NO) {
[UIView animateWithDuration:.6 animations:^{
leftView.center = CGPointMake(leftView.center.x + 100, leftView.center.y);
mainView.center = CGPointMake(mainView.center.x + 100, mainView.center.y);
} completion:^(BOOL finished) {
isRevealed = YES; ;
}];
}else{
[UIView animateWithDuration:.6 animations:^{
leftView.center = CGPointMake(leftView.center.x - 100, leftView.center.y);
mainView.center = CGPointMake(mainView.center.x - 100, mainView.center.y);
} completion:^(BOOL finished) {
isRevealed = NO;
}];
}
}
leftView and mainView are IBOutlets to the 2 container views. I call this method from a button in the main view controller (the root view controller of the navigation controller that's embedded in the large container view):
-(IBAction)callSlideIn:(id)sender {
[(ViewController *)self.navigationController.parentViewController slideInLeft];
}
I found a "fast" way to achieve this (and a bit hacky imo)
I added the leftMenu view to the top view in the views hierachy:
UIWindow* window = [UIApplication sharedApplication].keyWindow;
if (!window)
window = [[UIApplication sharedApplication].windows objectAtIndex:0];
[[[window subviews] objectAtIndex:0] addSubview:self.leftMenu.view];
Now it is les deep than the navigation bar and, of course, its clickable

How to hide custom tab bar button when hidesBottomBarWhenPushed is "TRUE"

I am using the code snippet from Tito to add a custom button to my tab bar:
https://github.com/tciuro/CustomTabBar
(Subclassing UITabbarController and adding a custom button using
// .. created a UIButton *button
[self.view addSubview:button];
)
This works great with my storyboard-based app except for the case of a subview within a navigation controller with the option "Hides bottom bar on push" enabled.
This hides the tab bar as promised, but not the custom button.
Seems like the button should be added as a subview to the tab bar itself?
I tried this ugly code which did not even make the button show up:
for(UIView *view in self.view.subviews)
{
if([view isKindOfClass:[UITabBar class]])
{
[view addSubview:button];
break;
}
}
Any ideas?
UPDATE:
My solution:
In my ApplicationDelegate i define the following methods, which i call whenever needed in the viewWillAppear or viewWillDisappear methods:
-(void)hideCenterButton:(BOOL)animated
{
if(animated){
[UIView animateWithDuration:0.3
delay:0.0f
options:UIViewAnimationCurveLinear
animations:^{
CGRect frame = self.centerButton.frame;
frame.origin.x = -100;
self.centerButton.frame = frame;
}
completion:^(BOOL finished){
}];
}
}
-(void)showCenterButton:(BOOL)animated
{
if(animated){
[UIView animateWithDuration:0.35
delay:0.0f
options:UIViewAnimationCurveLinear
animations:^{
CGRect frame = self.centerButton.frame;
frame.origin.x = (self.view.superview.frame.size.width / 2) - (self.centerButton.frame.size.width / 2);
self.centerButton.frame = frame;
}
completion:^(BOOL finished){
}];
}
}
I had to set the animation's duration to 0.35s to get a smooth effect in harmony with the tab bar.
Why don't you make button your tabbar's part.
tabBarController.tabBar.addSubView(yourButton)
everything would be solve. cheers!
One easy way to handle this would be to create an instance of the button in .h of your file.
UIButton *customTabButton;
When calling the hides bottom bar on push set the button property to hidden and reset it again in the other views if the bottom bar is visible.
shareFbButton.hidden=YES;
You can check this is the viewDidLoad of all the files and put this line of code if needed to make sure you are displaying the button and hiding the button on all the pages you need.
if(self.tabBarController.tabBar.isHidden){
// set or reset the custom button visibility here
}
This is one way.
I think there are 2 ways you can got with this.
1) try to get the button into a view that is above the old top view controller and the tab bar BUT below the new top view controller that is pushed.
2) animate away the button when the new view controller is pushed.
The first will require mucking with the iOS proprietary view hierarchy which is undocumented, unsupported and could change anytime.
The second will be a matter of making the animation appear smooth enough for your user not to notice. It's not entirely a matter of behaving perfect, just appearing appropriately.
I would personally recommend an animation of the the button disappearing (animate it's alpha to 0) and reappearing based on if your view controller that goes over the tab bar is appearing or disappearing.
The animation for a navigation is (I believe) 0.3 seconds. If the button is in the middle of the tab bar, you'll likely want it invisible as the animating in view controller reaches it (if not sooner) so something between 0.1 and 0.15 seconds could be used to animate it out.
Now this does not make the button behave exactly the same as the tab bar, but with the quickness of the transition being so short, it will be unnoticeable really to the user.
Now just to provide a question for you to ask yourself. Why do you need to push a view controller that overlaps the tab bar? Why is that more desirable/necessary than presenting a modal view controller? If you can strongly argue for it, keep at it and good luck, if it's not necessary however, you may be able to achieve the experience you want with a modal view controller.
Check this one to put a button on the UITabBar. See if it works after with hidesBottoBarWhenPushed.

UIViewController Won't Unload

I have been researching this question almost since I started learning to program for iOS (February 2012). I have read lots of posts on here which seem to be asking the same question and I have tried to implement the answers into my application to no avail. I am sure I am missing something simple.
I have a view switching test application. There are three views: orange, blue, yellow. It starts out on the orange view with two buttons - switch to blue view and switch to yellow view. When I click on switch to yellow view - the views revolve against a white background. The yellow view also has two buttons - switch to orange view and switch to blue view. When I click on switch to orange view the view flips back but instead of a white background the orange view is the background. How do I make that orange view not be there?
This is the code that I use to do the transition:
-(IBAction)switchToYellowView:(id)sender {
YellowViewController *myViewController = [[YellowViewController alloc]
initWithNibName:#"YellowViewController"
bundle:nil];
[UIView beginAnimations:#"flipview" context:nil];
[UIView setAnimationDuration:2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
forView:self.view cache:YES];
[self.view addSubview:myViewController.view];
[UIView commitAnimations];
}
From what I have read, I thought I needed to remove the orange view from the superview. But when I use
[OrangeViewController.view removeFromSuperView]
I get an error saying that "property view is not found on object OrangeViewController."
And if I switch from the yellow view to the blue view the orange view is still in the background. And then switching back to orange from blue, yellow is still in the background.
I read somewhere else, that I need to release these views also by adding
[myViewController release]
after I commit the animations. I thought that this was unnecessary when using ARC (which I am using). And when I do this, trying to go back to the orange view causes a Bad Access crash.
Perhaps I need to do something with rootViewController? I did set the OrangeView as a subview of "window" in the app delegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
[self.window addSubview:viewController2.view];
[self.window makeKeyAndVisible];
return YES;
}
viewController2 is a pointer to the OrangeViewController.
Because of the first comment, I started to look around for switching out rootViewController - and found Ken Anderson's lecture notes about switching the rootviewcontroller programatically. I can get the yellow to change in, but it isn't animating.
The next two comments are leading me in other directions - might the best thing be to use a containercontroller - like UITabBarController? Except use my own buttons and never display a tab bar?
I can, of course, provide the entire application for perusal. Thank you in advance!
Try to use:
[self transitionFromViewController:currentViewController toViewController:firstViewNav duration: options: animations:^{
} completion:^(BOOL finished){
}];
Inside switchToYellowView:, you are adding the yellow view as a subview of your current view, which is the orange view. Thus if you try to remove the orange view with [OrangeViewController.view removeFromSuperView] (which probably isn't working because view isn't a public property of OrangeViewController), then you would be removing the orange view which has the yellow view as a subview, effectively removing both from the window. I think what you want to do inside switchToYellowView is something like this:
[self.view removeFromSuperview]; //remove the orange view
[window addSubview:myViewController.view]; //replace it with the yellow view

Resources