Navigation Bar with different colors in every view-controller like Twitter (not with setbartintcolor) - ios

AS you can see in the image below, Twitter use different navigation bar color for each view-controller that is pushed.
I've tried almost everything (setbackgroundimage, backgroundcolor, bartintcolor, etc) but nothing seems to work. What i think is that Twitter use custom transition to SIMULATE the push, because, what it seems to me is that every view-controller is presented has his own navigation bar with his own color.

If you want to handle navigationBar with different barTintColors, Code School had a tutorial about it. (iOS App: Creating a Custom Nav Bar)
It could also extended to different backgrounds by using setBackgroundImage:forBarMetrics: method.
There are following four steps:
Handle this in viewWillAppear of the source view controller, hide the navigationBar that navigationController provided and create a new navigationBar to the superView.
- (void)styleNavBar
{
// 1. hide the existing nav bar
[self.navigationController setNavigationBarHidden:YES animated:NO];
// 2. create a new nav bar and style it
UINavigationBar *newNavBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 64.0)];
[newNavBar setTintColor:[UIColor whiteColor]];
// 3. add a new navigation item w/title to the new nav bar
UINavigationItem *newItem = [[UINavigationItem alloc] init];
newItem.title = #"Source";
[newNavBar setItems:#[newItem]];
// 4. add the nav bar to the main view
[self.view addSubview:newNavBar];
}
Do the same trick in viewWillAppear of the destination view controller, and create a backBarButtonItem as new navigationBar'sleftBarButtonItem.
- (void)styleNavBar
{
[self.navigationController setNavigationBarHidden:YES animated:NO];
UINavigationBar *newNavBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 64.0)];
[newNavBar setTintColor:[UIColor blueColor]];
UINavigationItem *newItem = [[UINavigationItem alloc] init];
newItem.title = #"Destination";
// BackButtonBlack is an image we created and added to the app’s asset catalog
UIImage *backButtonImage = [UIImage imageNamed:#"BackButtonBlack"];
// any buttons in a navigation bar are UIBarButtonItems, not just regular UIButtons. backTapped: is the method we’ll call when this button is tapped
UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithImage:backButtonImage
style:UIBarButtonItemStylePlain
target:self
action:#selector(backTapped:)];
// the bar button item is actually set on the navigation item, not the navigation bar itself.
newItem.leftBarButtonItem = backBarButtonItem;
[newNavBar setItems:#[newItem]];
[self.view addSubview:newNavBar];
}
Fill out the backTapped: method so that user is able to tap-to-popover from destination view controller.
- (void)backTapped:(id)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
Considering the swipe-to-pop situation, setting the gesture recognizer’s delegate to self in viewWillAppear of the destination view controller. (The author: The solution here is a bit of a hack.)
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self styleNavBar];
__weak id weakSelf = self;
self.navigationController.interactivePopGestureRecognizer.delegate = weakSelf;
}

This for swift3 :
You can set the original navbar background with an empty image:
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
With this all of the others VC in the view hierarchy will adopt an transparent nav bar.
In the other VC if you want to set an custom image or a custom color simply put a background view in the position of the navbar, this in the view did load method of the particular view controller.
let viewNavBar = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 64))
viewNavBar.backgroundColor = UIColor.white
view.addSubview(viewNavBar)
Whit this you can set any background or image inside the viewNavBar and don't mess with the overall configuration of the navigation bar.

Twitter doesn't change the navigation bar colour. When you're looking at a user's profile, it's a blurred version of the user's cover photo.
As you can see in the transition, the whole user profile view replaces the previous view. The navigation bar doesn't change, it is replaced. They might not even use a UINavigationBar (or at least not the one from the navigation controller).
The "bar" is a custom view that shows the user's cover photo, with the back/search/tweet buttons appearing in their usual positions. The user's cover photo shrinks, blurs and attaches to the top of the screen when you have scrolled down - and at this point, it looks like a normal navigation bar. The user's name and tweet count also scrolls up to the center of the navigation bar at this point.
It's quite intriguing, and their whole view structure for a user's profile probably uses a bunch of tricks. But it's not exactly a simple task to imitate their profile view, and they do much more than just change the tint of their navigation bar. If you just want to do this, Undo's answer works well. However, you may also have to reset the tint colour in your viewWillAppear method (of the old and new views).

Try look up this GitHub repo, I think it could help you achieve that effect https://github.com/kingiol/KDInteractiveNavigationController

Related

How do I add a back button to my UINavigationBar?

A user arrives at this viewController from the previous one through a push segue, so I want there to be a back button in the UINavigationBar to allow them to return.
Normally this back button would appear by default if I right clicked on the viewController in storyboard and selected Embed in > Navigation Controller, but doing this is causing crashes, and I prefer doing things programmatically, so I decided to do it in viewDidLoad like so:
// Nav bar
UINavigationBar *navbar = [[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
// Back Button
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style: UIBarButtonItemStyleBordered target:self action:#selector(Back)];
self.navigationItem.leftBarButtonItem = backButton;
[self.view addSubview:navbar];
This successfuly adds a navigation bar up top, but it doesn't add the back button as expected. I've tried the solutions given here, here, and here, but none have solved the problem.
You have constructed a UINavigationBar and a UIBarButtonItem but never connected the two.
UINavigationController manages a UINavigationBar for you and sets it's topItem to be the navigationItem of the topmost view controller in the navigation stack. If you need to build your own navigation bar then you need to manage it's item stack yourself. Take a look at UINavigationBar's - pushNavigationItem:animated: method.
However given that you seem to want the look and functionality of a UINavigationController it is unclear to me why you are adding a UINavigationBar view yourself instead of using that container view controller.

How to make Navigation Bar and Tab bar always visible on every screen even after implementing PushView controller

I have a iPhone app in which need to add UISearchbar on navigation bar, so that user can search from any where inside the app. When User Searches it displays search result in a Tableview controller and User can select any row which pushes to other controller.
Below is the Structure which i have in StoryBoard
Navigation Controller
Tab Bar Controller
View Controller1
View Controller2
View Controller3
View Controller4
I can successfully add the UIsearchbar on Navigationbar in ViewController 1
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:SEARCH]];
imageView.frame = CGRectMake(0, 0, 20, 20);
UITapGestureRecognizer *tapGesture =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(searchTapped:)];
[imageView addGestureRecognizer:tapGesture];
self.searchButton = [[UIBarButtonItem alloc] initWithCustomView:imageView];
self.searchButton.style = UIBarButtonItemStylePlain;
self.searchButton.target = self;
[self.searchButton setTintColor:[UIColor whiteColor]];
self.tabBarController.navigationItem.rightBarButtonItem = self.searchButton;
I can successfully implement the Search results as well in Tableview controller but when user select row it Pushes to different controller. Below is the code which implmenetd to push to different controller.
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
EntityViewController *entityController = [mainStoryboard instantiateViewControllerWithIdentifier:ENTITYIDENTIFIER];
entityController.dataDic = result;
[self.navigationController pushViewController:entityController animated:YES];
The problem here is when it pushes to different controller the TabBar is completely hidden and Navigation bar right button is completely Hidden.
I tried to Unhide the tab bar and Navigation bar but no effect. I tried all possibilities but nothing worked.
Can some one please let me know what is right approach to solve this issue.
Thanks In Advance.
Have you tried switching the order of the UINavigationController and the UITabController?
Right now, it seems like you have a UINavigationController with a UITabController "inside" it. So, when you push something else to the UINavigationController, the UITabController is being pushed aside, as it is no longer relevant.
If you were to have the UITabController on the top most level, with the UINavigationController at each of the tabs (or only on the relevant ones), when you'll push another view controller to that UINavigationController, it won't affect the tab bar, since it will still be on the top most level, completely unaffected by the push.
I hope this helps. Good Luck!
Thanks for the help. I resolved the issue by making Tab Bar controller as TOP View and Navigation controller for each view ( as per requirement. I made SearchController separately so that user can search from any where inside the app.
I updated this as it can be help full for those who needs to implement similar kind of requirement.
If there is a better approach of implementation please do provide your comments.
Thanks

How to transition smoothly from translucent to opaque UINavigationBar iOS?

I'm running into problems reconfiguring the UINavigationBar on iOS 7 and 8 when transitioning between views.
My application currently contains the following UIViewController flow:
VC1 --> VC2 --> VC3
In this flow
VC1 is the home screen and has an opaque UINavigationBar
VC2 has a translucent UINavigationBar
VC3 goes back to having an opaque UINavigationBar
The problem I've been running into is that the transitions between these views are all very sloppy looking. To start with I tried the following:
in VC2
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// configure appearance
[self.navigationController.navigationBar configureTranslucentAppearance];
}
And in VC1 and VC3
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// configure appearance
[self.navigationController.navigationBar restoreDefaultAppearance];
}
Here are the implementations of the two helper functions listed above:
- (void)restoreDefaultAppearance {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
[self setTitleTextAttributes:#{NSForegroundColorAttributeName: [UIColor JTTextNavBar]}];
[self setTintColor:[UIColor JTTextNavBar]];
[self setBarTintColor:[UIColor JTBackgroundNavBarWithAlpha:1.0]];
[self setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[self setBackgroundColor:[UIColor JTBackgroundNavBarWithAlpha:1.0]];
[self setShadowImage:[UIImage navigationBarShadowImage]];
[self setTranslucent:NO];
}
- (void)configureTranslucentAppearance {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
[self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self setBackgroundColor:[UIColor clearColor]];
[self setShadowImage:[UIImage new]];
[self setTranslucent:YES];
}
This is the most basic way of handling this transition. It has the following visual artefacts:
When going from VC1 --> VC2 the moment you begin the transition the navigation bar turns black. The animation completes normally
When going from VC2 --> VC1 the nav bar instantly changes to the application default colour before the segue has time to complete.
When going from VC2 --> VC3 the navigation bar instantly goes from translucent to the app nav bar color and then menu items and VC body animate in.
When going from VC3 --> VC2 the nav bar instantly turns black and remains this way until the segue is complete.
None of these transitions look good at all. Ideally I would like the views to transition smoothly along with their new UINavigationBar but the only way I've seen to do this successfully is to manually add a toolbar to each xib.
Any suggestions? Apologies if this description is confusing :(
Edit: Added cropped images of the UINavigationBar and top portion of UIViewController for each of the listed transitions.
I finally found a decent solution!
There doesn't appear to be a proper way to smoothly transition from an opaque to transparent UINavigationBar BUT you can transition smoothly from a view controller with a visible status bar to one that has a hidden status bar.
This opens up a possible workaround which is to add the following in the viewWillAppear of VC2 from above:
[self.navigationController setNavigationBarHidden:YES animated:YES];
Once you have that, manually add a UINavigationBar to your xib and configure it to be transparent (and add all necessary UIBarButtonItem and views).
If everything is hooked up properly transitioning from VC1 to VC2 will hide the UINavigationBar at the same speed as the view transition and VC2 will show up with it's embedded UINavigationBar
Note: To make this work properly you'll have to make sure that in the viewWillAppear of View Controllers that can be accessed from VC2 you reset the UINavigationBar to be visible (if necessary) via:
[self.navigationController setNavigationBarHidden:NO animated:YES];
TL;DR - manually add a UINavigationBar to your transparent nav bar view controller and in its viewWillAppear hide the default one via setNavigationBarHidden:animated:
The black color you're seeing is the background color of the UINavigationController's view. One way to minimize seeing it is to manipulate the background color of that view to the color of the outgoing / incoming view controller's view. This works well if you're working with solid colors. Another approach is to extend your views behind the opaque navigation bar using UIViewController.extendedLayoutIncludesOpaqueBars = YES;
Set the UIWindow background color to your Navigation bar's tintColor.
always use Translucent, plus add an uiview with a color below it and animate it's alpha?
I've struggled with a nearly identical problem. There really aren't any smooth transitions using either a nav bar or toolbar as a blur. The best option that I've found* is to make an image out of the view and then use that image for the transition. Especially if you just need it for transitions, it's just about the cheapest option that still provides a great UI/UX.
*The one caveat is that some of the UI effects in a nav bar and toolbar don't show up when you take a snapshot, screenshot, or rasterize a UIView as an image. This is negligible if used for a transition.
You can create your own navigation bar using just a UIView and that way you have complete control over its appearance, layout, fading etc.
I gave up using UINavigationBar a while ago as it can be a pain to work with, as you are discovering, and now I never ever use it.
I have a root view controller which has a UIView which represents the navigation bar. If I want to do something like add a back button, change the color, show the navigation bar or hide it, change the transparency, etc. that is all controlled by the RVC and other view controllers call methods on the RVC to change the navigation bar depending upon their appearance requirements.
The RVC has a container view which is the full size of the controller view and the other view controllers get loaded into that.
A little bit of configuration to get everything set up, but once done its a structure that can be used in every project that uses a navigation bar very quickly.
So I struggled with this too.
Unfortunately I didn't have any success adding my own navigation bar via the storyboard. Instead, (and I warn you this is hacky) I add a view in the ViewController with the opaque navigation bar that has a negative margin and extends under the navigation bar.
When the ViewController with the transparent navigation bar is pushed the bar then immediately becomes transparent but due to the identically coloured view I have place directly behind it the change isn't noticeable. Et voila.
The code I have is pretty basic and written in C# (Xamarin) but for reasons of completeness....
var backing = new UIView(new CGRect(0, -68, this.View.Frame.Width, 64f));
backing.BackgroundColor = UIColor.Green;
this.View.AddSubview(backing);
Change background color work for me
window?.backgroundColor = Color.red.toUIColor()
I have one more solution..for the ones who are now refactoring the project and cant add navigation bar everywhere.. This is not a perfect solution just like #alexgophermix one. But its not bad either:
let transition = CATransition()
transition.duration = 0.6
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
transition.type = kCATransitionFade
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.isTranslucent = true
navigationController?.navigationBar.layer.add(transition, forKey: nil)
navigationController?.view.backgroundColor = .clear
I am setting my nav bar in viewDidLoad() so this works everywhere and gives a slight different transition. In my case I was setting clear backgrounds somewhere and rest a gradient image. So this small change goes well for everywhere. This transition is not much noticeable but neither looks bad :)
In my case, the black I was seeing was the navbar's background image. Instead of setting it to nil, I set it to match the background color of the view behind the transparent navbar inside viewWillAppear:
let image = UIImage(color: .white)
navigationController?.navigationBar.setBackgroundImage(image, for: .default)
Then, inside willMove and viewWillDisappear I reverted it back to the original color.
YPNavigationBarTransition is a configureable framework animating navigation bars.
YPNavigationBarTransition uses two fake navigationbars (UIToolBar indeed) to simulate bar transitions while making the real navigationbar transparent.
Subclass your own UINavigationController and embed transitioncenter in it like YPNavigationController
Implement YPNavigationBarProtocol for your content controllers respectively.
Done.
A complete demo is include in the repo, checkout it for more details.

How to add Navigation bar to view controller with tab bar item

I have an app that uses bottom tabs aswell as a side menu, to have the button that initiates the side menu i use the typical three line menu button, to put that there I have a Navigation Bar. With the bar in place there is no way I can get the bar to be on top of the screen. I built it with interface builder, and heres a screenshot. The question is how do i have the navigation bar alone without the other grey bar above it?
The issue you're encountering is due to the fact that you're manually creating a navigation bar for your view controller, instead of using the bar that you get for free by embedding the view controller in a tab bar controller, hence the reason you see two bars. The other answer suggesting hiding the auto-generated navigation bar is not the correct solution. Instead, you should place your menu button and view title in the auto-generated bar instead of manually creating your own (you almost never want to do that, in-fact).
So what you should do instead is set the title property of your view controller to be "News", and the leftBarButtonItem property of the view controller to be your hamburger menu button (an instance of UIBarButtonItem initialized with an image for the icon).
For example (inside your view controller's viewDidLoad method or wherever appropriate):
self.title = #"News";
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"menuIcon"] style:UIBarButtonItemStylePlain target:self action:#selector(showSideMenu)];
If you want to remove the topmost navigation bar you need use self.navigationController.navigationBarHidden = YES; for view controllers that used for tabs in UITabBarController:
// StoriesViewController.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = YES;
}

ios force back button style w/ no navigation controller

I'm not using a navigation controller so I'm just getting a plain rounded rect. I want to get the arrow-esque back button instead, is that possible?
From your comments, you would like to use a navigation controller but don't have room for the navigation bar on your root view controller.
self.navigationController.navigationBarHidden
Will hide or show the navigation bar within a view controller. That should make your life simpler.
It is rather simple, create your custom back button like so:
UIButton *button = /* your custom button, most likely with an image */
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
[self.navigationItem setRightBarButtonItem:barButtonItem];

Resources