Is it correct to move the navigation bar frame? - ios

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

Related

Create a submenu iOS

I want to create a submenu that will appear right next to the first menu and that will contain more options. The first menu is hidden and only appears when a button its clicked on the navigation bar, i used the SWRevealViewController from github for the first menu, but i can't make the second one appear . Can somone help ?
Thanks for any help in advance
Basically you add another SWRevealController as front view controller of the root SWRevealController.
UIViewController *secondRearVC = // your second level menu controller
UIViewController *secondVC = // your second level front view controller
SWRevealViewController *childRevealController =
[[SWRevealViewController alloc] initWithRearViewController:secondRearVC frontViewController:secondVC];
[rootRevealController setFrontViewController:childRevealController animated:YES];
You can find example of what I've suggested here.
Other option is using other side menu controller, JASidePanels, if I'm not wrong it does what you want. Anyway you'll end up using some UIViewController containers recursively, so it's just a matter of choice.
For this effect i have created a separate view say reveal view with UITableView init, at first i am giving zero width and full height for that view. If the navigation button is pressed , i am moving the main view to right like about 100px and change the width of the reveal view to 100px, place that code in animation block.
[UIView animateWithDuration:0.5 animations:^{
//Move frame or transform view
revealView.frame = CGRectMake(0,0,1,screenHeight);
mainView.frame = CGRectMake(0, 0, 320, screenHeight);
}];

UINavigationBar frame animation not possible?

UINavigationBars within a UINavigationController. . . they don't participate in frame animations. Useful, but exactly not what I want right now. Is there a way to turn this off?
I know I could set the showsNagitationBar property to hidden, and add my own to the view, put am looking at possible alterntives.
What I'm Trying to Achieve:
I've put my UINavigationController into a (screen-sized) container view, and want to slide it across to reveal a side menu. . last time that I did this I had custom push/pop methods on the RootVC, and my own navigation bar - worked fine, though a fair amount of boiler-plate code to set up.
This time I've got the same kind of requirement - main content is push/pop based, and some auxiliary VCs that can be revealed from the side. And so for another approach, and considering that this app's look and feel is very standard, I just included a UINavigationController within the RootVC and expected it to work the same.
However the UINavigationBar stays anchored in place, while the rest of the content within the container view moves.
I am not entirely sure what you are trying to achieve, but when using a navigation controller, the entirety of what you see on screen (your top view controller's view PLUS your navigation bar) is rooted in the Navigation Controller's view.
This means that if you do something like:
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.navigationController.view.frame;
frame.size.width -= 30;
self.navigationController.view.frame = frame;
}];
You will get your view AND the navigation bar to shrink.
EDIT: You can add/remove the sliding-in views to the navigation controller's view where it is appropriate (for example the nav controller is your root view controller, you could do it in your appdelegate's didFinishLaunch: method). The following code would show an entirely red view sliding in from the left. In your case, this view would be the one from your side view controller.
UIView *left = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
left.backgroundColor = [UIColor redColor];
CGRect ff = left.frame;
ff.origin.x = -ff.size.width;
left.frame = ff;
[self.navigationController.view addSubview:left];
[UIView animateWithDuration:1.0 animations:^{
CGRect frame = self.navigationController.view.frame;
frame.origin.x += 50;
self.navigationController.view.frame = frame;
}];
Is something like this what you were looking for?

uitableview with header like instagram user profile

I've been struggling with this for quite a while now.
I have to implement an user profile similar to what Instagram has in their ios app.
When clicking on the first to buttons on that tab bar like thing all the contents downwards from it changes. The tableview that is displayed on the bottom part has dynamic size so they keep account of that also.
I have something implemented where the top part is a UIView with 5 buttons and based on them the bottom part (witch is like a container view) changes content. And these two (top uiview and bottom container view) are part of UIScrollView. But this way I can't get information back in time on the size about the tableview's size that I want to display in the bottom part in order to modify the UIScrollView's size. And I have a feeling this is a flawed way to do it.
I would really appreciate any ideas oh how to implement this king of interaction. Thank you.
I believe it's a headerView on a UITableView or a UICollectionView, depending on which view mode you have selected. When you tap one of the buttons it changes out the UITableView to a UICollectionView or vice versa.
You want to keep track of the current contentOffset for whichever is being displayed (UICollectionView and UITableView are both subclasses of UIScrollView so you will be able to get this from both) and then set the contentOffset on the view you're switching to.
Setup an ivar for the UIView header subclass so you can easily re-use it.
This is what I have. My problem is that I'm mot getting back in useful time the tableview's frame height from the tableview controller to the UserProfileViewController in order to change the latter's scrollview size. I also feel that I'm somehow doing this backwards so any suggestions are more than welcome.
This view has two parts: an upper part and a lower part. The parent view is a scroll view. What I wanted to achieve with this is having a sort of tab bar in the upper part that will controll waht will appear in the lower part.
The upper part has a flip animation when the upper left button is pressed to reveal another view.
The way this is achieved is by having 2 views: a dummy view and the back view. The dummy view has the front view as a child. The front view is the one that containes all the buttons.
The code for this animation is achieved in this way:
- (IBAction)infoButtonPressed:(id)sender
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.hoverView cache:YES];
if ([self.headerView superview]) {
[self.headerView removeFromSuperview];
[self.hoverView addSubview:self.backOfHeaderView];
[self.infoButton removeFromSuperview];
[self.backOfHeaderView addSubview:self.infoButton];
} else {
[self.backOfHeaderView removeFromSuperview];
[self.hoverView addSubview:self.headerView];
[self.infoButton removeFromSuperview];
[self.headerView addSubview:self.infoButton];
}
[UIView commitAnimations];
}
The lower part is made out of a container view that acts as a place holder.
When a button is pressed a different view controller is displayed in the container view.
Each view controller has a container view of it's own. The specific view of that view controller (tableview) is added to it's container view when the controller is loaded. It also makes sure that if the tableview is already added to the container view it will be removed. All this is done in each specific view controller.
In the view controller of the User Profile view there is an instance of the container view and one of a UIViewController that also acts as a placeholder(named currentViewController from now on). When a specific button is pressed it checks if the an instance of the view controller that we want to display already exists. If not it will make one and will set it's tableview's frame to the bounds of the container view. After that it will remove the currentViewController's view from the superview and the currentViewController itself from the parent viewcontroller to make sure that if there is something assigned to these they will not be there. Then it goes and assigns the desired viewcontroller to the currentViewController. It also assigns the desired viewcontroller's containerView instance to the containerview in the parent viewcontroller (the User Profile viewcontroller). At the end it will add the desired viewcontroller as a child to the main viewcontroller (the User Profile viewcontroller) and desired viewcontroller's view to the containerView of the main viewcontroller.
This is the code for one of the buttons:
//Check if there is an instance of the viewcontroller we want to display. If not make one and set it's tableview frame to the container's view bounds
if(!_userWallViewController) {
self.userWallViewController = [[WallViewController alloc] init];
// self.userWallViewController.activityFeedTableView.frame = self.containerView.bounds;
}
[self.userWallViewController.containerView addSubview:self.userWallViewController.activityFeedTableView];
//If the currentviewcontroller adn it's view are already added to the hierarchy remove them
[self.currentViewController.view removeFromSuperview];
[self.currentViewController removeFromParentViewController];
//Add the desired viewcontroller to the currentviewcontroller
self.currentViewController = self.userWallViewController;
//Pass the data needed for the desired viewcontroller to it's instances
self.userWallViewController.searchURLString = [NSString stringWithFormat:#"event/user/%#/", self.userID];
self.userWallViewController.sendCommentURLString = [NSString stringWithFormat:#"event/message/%#", self.userID];
self.userWallViewController.totalCellHeight = ^(float totalCellHeight){
self.userWallViewController.numberOfCells = ^(float numberOfCells){
NSLog(#"The total number of cells: %f", numberOfCells);
NSLog(#"The total cell height: %f", totalCellHeight);
self.scrollView.contentSize = CGSizeMake(320.0, totalCellHeight + 172.0 + 33.0);
CGRect newFrame = self.userWallViewController.containerView.frame;
newFrame.size.height = totalCellHeight + 33.0;
self.userWallViewController.containerView.frame = newFrame;
NSLog(#"Container view: %f", self.containerView.frame.size.height);
NSLog(#"Scroll view: %f",self.scrollView.contentSize.height );
};
};
//Add this containerview to the desired viewcontroller's containerView
self.userWallViewController.containerView = self.containerView;
//Add the needed viewcontroller and view to the parent viewcontroller and the containerview
[self addChildViewController:self.userWallViewController];
[self.containerView addSubview:self.userWallViewController.view];
[self performSelector:#selector(changeScrollView) withObject:self afterDelay:0.5];
//CLEAN UP THE CONTAINER VIEW BY REMOVING THE PREVIOUS ADDED TABLE VIEWS
[self.userFansViewController.userSimpleTableView removeFromSuperview];
[self.fanOfViewController.userSimpleTableView removeFromSuperview];
[self.userPublishedMovellaListViewController.gridView removeFromSuperview];
[self.userPublishedMovellaListViewController removeFromParentViewController];
self.userPublishedMovellaListViewController = nil;
}
I know this answer is over a year late, but I wanted to state my hypothesis on it...just incase it might help someone else later. Im implementing a similar view and came to this conclusion. Anyone is welcomed to correct me if I'm wrong.
I think that perhaps the top view is a header view and the two options that seem like a collection view and a table view are both collection views.
Because the layout of collection views can be fine tuned to the most minute details, I think the view that looks like a table view is just a really specifically designed collection view. And when switching between the views, the collection view's data and properties are being swapped and reloaded.

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");
}];
}

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.

Resources