I want to developer app with a custom navigation bar like in the following images:
I think that i need to subclass UINavigationBar and add button to centre of nav bar, but i don't really know how to make navigation bar look like on image. Can you please give me advice what should i do, links to any kind of documentation would be awesome!
Similar questions about navBar that doesn't helped me:
ios back button in the bar
Use custom Navigation Bar in iOS
Custom Navigation Bar in iOS 5
rogcar
EDIT:
My idea is next: make custom navigation bar height little bigger than default size, and add background image with arrow in it and with some transparency on the edges.
If you want a button (you probably do want) you can achieve it completely by subclassing UINavigationBar. You should remember that height of UINavigationBar is read-only property.
Style but not tappable:
So let's assume we subclass the navigation bar and add button there. You could do this and it will be going look great. For example:
- (void)drawRect:(CGRect)rect
{
self.backgroundColor = [UIColor lightGrayColor];
UIButton *myButton = [[UIButton alloc] initWithFrame:CGRectMake(self.frame.size.width/2-50, 0 , 100, 100)];
[myButton setBackgroundColor:[UIColor lightGrayColor]];
[myButton setTitle:#"Normal" forState:UIControlStateNormal];
[myButton setTitle:#"Highlighted" forState:UIControlStateHighlighted];
[self addSubview:myButton];
[self sendSubviewToBack:myButton];
}
But you will facing a problem that your button is non tapeable below UINvaigationBar. (I post an image on the bottom of the answer)
So there is clearly not a path you want to follow. Don't even try that.
Style but not tappable 2:
You may override this method in your navigation bar subclass
- (CGSize) sizeThatFits:(CGSize)size {
return CGSizeMake(custom_width, custom_height);
}
And then mask it using UIBezierPath for example
The right (tappable) way:
You have to create a view stick to your UINavigationBar. What i will do here (if you want it to every screen) is:
Make a Category of UIViewController which can draw (for example - this is easiest way) UIButton.
Style this 'UIButton' whatever you want (if you want
Pin action to 'UIButton': [btn addTarget:self action:#selector(menuShow:) forControlEvents:UIControlEventTouchUpInside];
menuShow: method should be declare in your category
You can call drawing button every time you want to redraw view controller.
As you can see there there will be two separates View: UINavigationBar and UIButton. This is allow you to set content under this little button and make it tapable.
So why just don't hide navigation bar, and use different view? Because iOS7 ;) When Apple change it in iOS7 for example then you have to rebuild your pseudo NavigationBar, with only additional view, you don't need to do anything.
You do not need to subclass UINavigationBar. Create UIView add to it UIImageView as background with image in the shape you need, add button.
Subclass UINavigationController hide UINavigationBar, add custom navigation bar.
First Hide navigation bar using -
self.navigationController.navigationBarHidden = YES;
Then create UIView with required height,height of navigationBar is 44px.Then create background image view, object of required UIButton and add all objects on created UIView as a subview.It will look like navigationBar.Thank you.
You can add your custom shaped view as titleView on the navigation bar.
Just make sure that clipsToBounds is set to NO, so it doesn't get clipped.
Related
I have a container view with two views and a toolbar. In the ContainerViewController I have "deactivated" the shadow of the navigation bar using this code (from Apple's library):
[self.navigationController.navigationBar setShadowImage:[UIImage imageNamed:#"TransparentPixel"]];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"Pixel"] forBarMetrics:UIBarMetricsDefault];
Also I have implemented the UIToolbarDelegate and its method
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar
{
return UIBarPositionTop; //or return UIBarPositionTopAttached;
}
But the shadow of the toolbar is still between the navigation bar and the toolbar and not underneath the toolbar, to separate the toolbar from the content.
Any ideas why the shadow doesn't change? Or how to check, if the toolbar position is position really TopAttached.
Edit:
I try to do something like described in this post: UISegmentedControl below UINavigationbar in iOS 7 without the searchbar.
As explained there, there are two shadows, the one of the navigationbar in the navigationcontroller, that is between navbar and toolbar. And the shadow of the toolbar.
I was able to deactivated the shadow of the navigationbar as described. It works also in the viewDidLoad:
But the shadow of the toolbar is in the wrong position. Using the positionForBar: method it should be in the button of the toolbar, but it stays in the top (between Navbar and Toolbar).
So I am looking for the fault, why it does not change.
You didn't specify what method you tried to change the shadow in, but I'm going to guess that you're trying to do it in viewDidLoad:
Your navigationBar does not actually exist in viewDidLoad, instead change the shadow in viewWillAppear: like this:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController.navigationBar setShadowImage:[UIImage imageNamed:#"TransparentPixel"]];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"Pixel"] forBarMetrics:UIBarMetricsDefault];
}
The iOS7 Facebook App has a right side menu that can be shown by swiping right to left or clicking on the upper right button. When this menu is opened the there is a color transition in the entire status bar from blue to black and vice-versa when closed.
This image shows both status bar side-to-side
This looks like a very good solution for iOS Apps with side menus.
Any ideas or ways about how to accomplish this?
I am currently using JASidePanels.
Thanks!
I managed to find a very simple, elegant way to do this, that mimics the Facebook app functionality perfectly.
Here's my approach:
Create view with status bar frame
Set view background color to black, opacity to 0
Add view as subview to any root view (you need a view that will cover both the center view and the menus, so that it won't be confined to any single view - a good option for this is the container view controller used by your menu controller implementation)
Set view's opacity in your menu controller implementation's menu animation method
Here's my specific implementation, using MMDrawerController:
I subclassed MMDrawerController (I actually already had a subclass for using MMDrawerController with storyboards), and added this code to the class's init method:
// Setup view behind status bar for fading during menu drawer animations
if (OSVersionIsAtLeastiOS7()) {
self.statusBarView = [[UIView alloc] initWithFrame:[[UIApplication sharedApplication] statusBarFrame]];
[self.statusBarView setBackgroundColor:[UIColor blackColor]];
[self.statusBarView setAlpha:0.0];
[self.view addSubview:self.statusBarView];
}
// Setup drawer animations
__weak __typeof(&*self) weakSelf = self; // Capture self weakly
[self setDrawerVisualStateBlock:^(MMDrawerController *drawerController, MMDrawerSide drawerSide, CGFloat percentVisible) {
MMDrawerControllerDrawerVisualStateBlock block;
block = (drawerSide == MMDrawerSideLeft) ? [MMDrawerVisualState parallaxVisualStateBlockWithParallaxFactor:15.0] : nil; // Right side animation : Left side animation
if(block){
block(drawerController, drawerSide, percentVisible);
}
[weakSelf.statusBarView setAlpha:percentVisible]; // THIS IS THE RELEVANT CODE
}];
I also added self.statusBarView as a private property.
The first section of code creates a view, configures it, and adds it as a subview of the MMDrawerController subclass's view. The OSVersionIsAtLeastiOS7() method is a custom method that simplifies the check to see if the device is running iOS 7 (if it isn't, your custom view will show up below the status bar, which you don't want).
The second section of code is MMDrawerController's setDrawerVisualStateBlock method, which sets the animations code to be performed when a menu is being opened and closed. The first few lines of code are boilerplate code that sets one of the prebuilt animations blocks to each menu (I wanted parallax on the left, but nothing on the right). The relevant code is the last line of the block: [weakSelf.statusBarView setAlpha:percentVisible];, which sets the status bar view's opacity to match the percentage that the menu is currently open. This allows for the smooth cross animation you see in the Facebook app. You'll also notice I've assigned self to a variable weakSelf, so as to avoid the "retain cycle" compiler warning.
This is my specific approach using MMDrawerController and a subclass, which I did more for convenience because I already had the subclass in place, than because it is necessarily the best approach or the only way to do it. It could probably be implemented in several other ways, using MMDrawerController without a subclass, or using any other side-drawer menu implementation.
The ending result is a smooth fading to black animation behind the status bar, exactly as you see in the new Facebook app.
I've been trying to accomplish the same thing. The method I am using to do this is based on the following concepts:
A background image with a height of 64 points will fill both the
UINavigationBar and the UIStatusBar.
A background image with a height of 44 points will fill the UINavigationBar and leave the
UIStatusBar black.
You can add an subview to the top of the current navigationController's view and it will sit underneath the UIStatusBar.
So, first, you need to create two images with your desired UINavigationBar look:
A 640x128px image to cover navigation bar and status bar (ImageA)
And a 640x88px image to cover the navigation bar but leave the status bar black (ImageB).
In the application:didFinishLaunchingWithOptions: method, set the background of your UINavigationBar with ImageA with [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"ImageA.png"] forBarMetrics:UIBarMetricsDefault];
When the side menu starts to open, you are going to want switch the UINavigationBar so it uses ImageB and create a view which you will add underneath the UIStatusBar. Here is some sample code for doing just that:
// Add a property for your "temporary status bar" view
#property (nonatomic, strong) UIView *temporaryStatusBar;
And in the code where the side menu starts to open:
// Create a temporary status bar overlay
self.temporaryStatusBar = [[UIView alloc] initWithFrame:[[UIApplication sharedApplication] statusBarFrame]];
self.temporaryStatusBar.backgroundColor = [UIColor yourColor];
[self.navigationController.view addSubview:self.temporaryStatusBar];
// Update both the current display of the navigationBar and the default appearance values
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"imageB.png"] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"imageB.png"] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setNeedsDisplay];
As the side menu animates open, or as the user pans the menu, all you need to do then is adjust the alpha level of the UIStatusBar overlay. When the side menu is fully open, the UINavigationBar should have ImageB as its background image and the UIStatusBar overlay should have an alpha of 0. When the side menu closes, you'll want to replace the UINavigationBar background with ImageA and remove the UIStatusBar overlay.
Let me know if this works for you!
You can use this awesome slide menu library
https://github.com/arturdev/AMSlideMenu
In this demo project you can see how to do that by writing 4 lines of code.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Setting navigation's bar tint color
self.navigationController.navigationBar.barTintColor = [UIColor colorWithHex:#"#365491" alpha:1];
// Making view with same color that navigation bar
UIView *statusBarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)];
statusBarView.backgroundColor = [UIColor colorWithHex:#"#365491" alpha:1];
// Replace status bar view with created view and do magic :)
[[self mainSlideMenu] fixStatusBarWithView:statusBarView];
}
I want to change the background image of my UIBarButtonItems. In the root view, I want them to be a certain background image (but still rounded-rect buttons) in the nav bar, but in the next view, I have a UIToolBar where I want it to have different backgrounds yet again.
I used [[UIBarButtonItem] appearance] in my app delegate to change all of them, but I now realize for some I want it one style and for others yet another.
More importantly, I want to change not only the background image, but the shape for some. For one of the UIToolBar's UIBarButtonItems I want it to be in the shape of a back button in the navigation bar. How would I achieve this look?
Can I achieve both of these with the method outlined here?
Basically: How do I make custom UIBarButtonItems all over the app, and have some with different shapes?
If you want the buttons to look different in different view controllers, you should set them within the view controller, not in the delegate. Add code in either the init method or the viewWillAppear: method to customise the buttons. If you are customising UIToolbar items then use code similar to the link you gave. If it's for the navigation bar, do something like this:
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
//Customise button with background etc that you want
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:btn];
self.navigationItem.leftBarButtonItem = item;
//Release item if you're not using ARC
You can use the 'appearanceWhenContainedIn' method from the UIAppearance Protocol http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAppearance_Protocol/Reference/Reference.html
So for the Toolbar, you'd use:
[UIBarButtonItem appearanceWhenContainedIn:[UIToolbar class], nil]
And for the NavBar:
[UIBarButtonItem appearanceWhenContainedIn:[UINavigationController class], nil]
To customize my navigation bar, I did several steps:
create a subclass which inheriting from UINavigationBar class, do some customization like draw shadow or setting background image for the navigation bar.
create an empty xib file, which contains nothing but a navigation view controller.
set the class name for the navigation bar in the navigation view controller.
Everything works fine, but when I want to add another customized back button on the navigation bar, I tried to attach a UIBarButtonItem to the navigationItem.backbarbuttonitem, I have no idea how to get the navigationItem from the UINavigationBar subclass.
code sample:
// header file
#interface MyNavigationBar : UINavigationBar
#end
// implementation file
#implementation MyNavigationBar
-(void)drawRect:(CGRect)rect
{
// background image
UIImage* background_image = [UIImage imageNamed:#"my-navigation-bar.png"];
[self setBackgroundImage:background_image forBarMetrics:UIBarMetricsDefault];
// draw shadow
self.layer.masksToBounds = NO;
self.layer.shadowOpacity = 0.6;
self.layer.shadowOffset = CGSizeMake(0, 3);
}
#end
Is there any way to get the navigationItem entry in my customized UINavigationBar subclass, or I just did it the wrong way? :P
thanks :)
you can hide the uinavigationbar. then put a uiview which can have height and width of uinavigationbar. and then add as many as buttons can fit or you want. add uiimage to the view. you will have a nice customized uinavigation bar. you can mimic the back button by using popviewcontroller or poptorootviewcontroller.
I have Storyboard in my project. I use [UIBarButtonItem setCustomView:] method to customize toolbar buttons. For example:
[self setCustomView:[[UIImageView alloc] initWithImage:image]];
Now they looks as I need. But I found that this method somehow disables segue that I set for this toolbar item. I mean, segue works without it, but when I tried to use this method for customization segue don't work. But why?
I don't want to use target-action pattern from code, I believe it is possible to use only Storyboard.
I've been trying to configure all of the segues in the storyboard as well but I needed to create a custom view for the rightBarButtonItem. To make sure the segue still works, just add this line before setting the customView:
[filterButton addTarget:self.navigationItem.rightBarButtonItem.target action:self.navigationItem.rightBarButtonItem.action forControlEvents:UIControlEventTouchUpInside];
This way the segues you set up in your storyboard will still fire with customViews.
My entire custom button code looks like this:
UIButton *filterButton = [UIButton buttonWithType:UIButtonTypeCustom];
[filterButton setImage:[UIImage imageNamed:#"filter"] forState:UIControlStateNormal];
[filterButton setFrame:CGRectMake(0, 0, 36, 36)];
[filterButton addTarget:self.navigationItem.rightBarButtonItem.target action:self.navigationItem.rightBarButtonItem.action forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.rightBarButtonItem.customView = filterButton;
I've tried what you have done with the same result - the picture is correct but the UIBarButtonItem doesn't react when pressed. Possibly this is a bug. My work around is as follows:
To do this in storyboard add a UIButton to the tool bar. You should see that storyboard adds it by putting the UIButton inside of the UIBarButton. Add the segue on the UIButton. Customize the UIButton in storyboard. In my App I set the size to 40 x 40. Then in your code customize the UIButton with the view. Here is an example of the code to add the imageView to the UIButton:
[sampleImageView setFrame:CGRectMake(0, 0, 40, 40)];
[swapButton addSubview:sampleImageView];
Note: Storyboard can be quirky about adding UIButtons to toolbars. It seems as if you do it in a toolbar that is tied to a navigation controller it won't let you add it. I've worked around this by adding a dummy view controller to the storyboard, adding a toolbar to that, then dragging the UIButton into that toolbar. Storyboard will create that for you by encapsulating the UIButton in a UIButtonBarItem. You can then copy then over to the the desired toolbar in your project and delete dummy view controller.
There are other ways to do this such as creating the buttons in code and adding them to the toolbar. The method above minimizes code.