I need to implement menu for iOS like android.menu
means button on navigation bar(right side).
If I click that menu will display.
I am using a storyboard.
I need to implement menu for iOS like android.menu
means button on navigation bar(right side).
If I click that menu will display.
I am using a storyboard.
So you want something like this:
Even works in landscape:
I think it's going to take forever for me to explain :D
Basically I created a custom UINavigationController as mentioned in the comments above, called it ActionBarNavigationController
From this custom UINavigationController, I added a custom UIView to display the ActionBar
with the drop down button on the right.
The drop down menu is a UITableView
with a populated list of your choice.
I used protocol
in iOS to handle the tap even on each row of the drop down menu.
Everything was done purely in code. You can add these files to your project if you like, I've provided the code in full below where necessary.
#import "AppDelegate.h"
#import "ActionBarNavController.h"
#import "ViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// ----------------------------------------------------------------------
// Our custom UINavigationController will contain the
// Android styled action bar as a subview as well as the
// drop down list.
//
// You can probably set the menu list items inside each individual
// controller instead of here. This is just for demo purpose.
// ----------------------------------------------------------------------
ActionBarNavController *actionBarNavController = [[ActionBarNavController alloc] init];
// ----------------------------------------------------------------------
// Initialize our main view controller and add it to
// action bar navigation controller.
// ----------------------------------------------------------------------
ViewController *viewController = [[ViewController alloc] init];
actionBarNavController.viewControllers = @[viewController];
self.window.rootViewController = actionBarNavController;
[self.window makeKeyAndVisible];
[actionBarNavController setNavTitle:@"Action Bar"];
// telling the controller the drop down list items
[actionBarNavController setMenuList:@[@"Action1", @"Action2", @"Action3"]];
return YES;
}
ViewController is just your ordinary UIViewController that conforms to the ActionBarNavControllerDelegate
that I created in the class below. Make sure you include it.
#import <UIKit/UIKit.h>
#import "ActionBarNavController.h"
@interface ViewController : UIViewController <ActionBarNavControllerDelegate>
@property (nonatomic, strong) ActionBarNavController *navController;
@property (nonatomic, strong) UILabel *lblMessage;
@end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// store the nav controller for easy access
self.navController = (ActionBarNavController *)self.navigationController;
self.navController.actionBarDelegate = self;
[[UIApplication sharedApplication] setStatusBarHidden:NO];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
[self initViews];
[self initConstraints];
}
-(void)initViews
{
self.view.backgroundColor = [UIColor whiteColor];
self.lblMessage = [[UILabel alloc] init];
self.lblMessage.text = @"This is your main view controller.\n\nPress the top right action bar button to see drop down menu.";
self.lblMessage.font = [UIFont systemFontOfSize:20];
self.lblMessage.numberOfLines = 0;
self.lblMessage.lineBreakMode = NSLineBreakByWordWrapping;
self.lblMessage.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:self.lblMessage];
}
-(void)initConstraints
{
self.lblMessage.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{
@"lblMessage": self.lblMessage
};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[lblMessage]-20-|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[lblMessage]|" options:0 metrics:nil views:views]];
}
#pragma mark - DropDownMenu Delegate Methods -
-(void)actionBarDropDownChosenItem:(NSString *)chosenItem
{
if([chosenItem isEqualToString:@"Action1"])
{
self.lblMessage.text = @"You have chosen action 1";
}
else if([chosenItem isEqualToString:@"Action2"])
{
self.lblMessage.text = @"You have chosen action 2";
}
else if([chosenItem isEqualToString:@"Action3"])
{
self.lblMessage.text = @"You have chosen action 3";
}
// hide actionBar drop down list
[self.navController hideDropDownMenu];
}
@end
This ActionBarNavController contains an instance of the ActionBar custom view. It handles the interactions of the user tapping on the drop down button.
#import <UIKit/UIKit.h>
#import "ActionBar.h"
// ------------------------------------------------------------
// Protocol is for handling when user selects an action
// from the drop down list, we need to inform any conforming
// delegate view controller the option was chosen.
// ------------------------------------------------------------
@protocol ActionBarNavControllerDelegate <NSObject>
@optional
-(void)actionBarDropDownChosenItem:(NSString *)chosenItem;
@end
@interface ActionBarNavController : UINavigationController <UITableViewDataSource, UITableViewDelegate>
// actionBar is a custom subclass that looks like Android's action bar
@property (nonatomic, strong) ActionBar *actionBar;
// the tableview will be our drop down list
@property (nonatomic, strong) UITableView *tableView;
// a boolean flag for toggling drop down menu
@property (nonatomic, assign) BOOL dropDownVisible;
@property (nonatomic, strong) NSArray *arrMenuItems;
@property (nonatomic, weak) id<ActionBarNavControllerDelegate> actionBarDelegate;
-(void)setNavTitle:(NSString *)navTitle;
-(void)setMenuList:(NSArray *)menuItems;
-(void)showDropDownMenu;
-(void)hideDropDownMenu;
@end
#import "ActionBarNavController.h"
#import "DropDownCell.h"
@interface ActionBarNavController ()
@end
@implementation ActionBarNavController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self initViews];
[self initConstraints];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Setup Methods -
-(void)initViews
{
self.view.clipsToBounds = YES;
// hide default navigation bar
[self setNavigationBarHidden:YES animated:NO];
self.navigationBar.translucent = NO;
// using our own custom looking action bar
self.actionBar = [[ActionBar alloc] init];
[self.actionBar.btnMenu addTarget:self action:@selector(toggleMenu) forControlEvents:UIControlEventTouchUpInside];
// setting up drop down list using a UITableView
self.tableView = [[UITableView alloc] init];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.alpha = 0;
self.tableView.backgroundColor = [UIColor colorWithRed:0.15 green:0.15 blue:0.15 alpha:1.0];
self.tableView.rowHeight = 50;
self.tableView.scrollEnabled = NO;
[self.view addSubview:self.actionBar];
[self.view addSubview:self.tableView];
}
-(void)initConstraints
{
self.actionBar.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{
@"actionBar": self.actionBar,
@"tableView": self.tableView
};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[actionBar]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[tableView(200)]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[actionBar(70)][tableView(150)]" options:0 metrics:nil views:views]];
}
#pragma mark - Other Methods -
-(void)setNavTitle:(NSString *)navTitle
{
self.actionBar.lblTitle.text = navTitle;
[self.view layoutIfNeeded];
}
-(void)setMenuList:(NSArray *)menuItems
{
self.arrMenuItems = menuItems;
[self.tableView reloadData];
}
#pragma mark - Drop Down Button Methods -
-(void)toggleMenu
{
if(self.dropDownVisible)
{
self.dropDownVisible = NO;
[self hideDropDownMenu];
}
else
{
self.dropDownVisible = YES;
[self showDropDownMenu];
}
}
-(void)showDropDownMenu
{
self.dropDownVisible = YES;
[UIView animateWithDuration:0.15 animations:^{
self.tableView.alpha = 1.0;
}];
}
-(void)hideDropDownMenu
{
self.dropDownVisible = NO;
[UIView animateWithDuration:0.15 animations:^{
self.tableView.alpha = 0.0;
}];
}
#pragma mark - TableView Methods -
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.arrMenuItems.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"cellID";
DropDownCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if(cell == nil)
{
cell = [[DropDownCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.lblTitle.text = self.arrMenuItems[indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Remove seperator inset
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
// Prevent the cell from inheriting the Table View's margin settings
if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
[cell setPreservesSuperviewLayoutMargins:NO];
}
// Explictly set your cell's layout margins
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.actionBarDelegate respondsToSelector:@selector(actionBarDropDownChosenItem:)])
{
[self.actionBarDelegate actionBarDropDownChosenItem:self.arrMenuItems[indexPath.row]];
}
}
@end
This ActionBar class is the custom UIView to show the action bar with drop down button.
#import <UIKit/UIKit.h>
@interface ActionBar : UIView
@property (nonatomic, strong) UIView *container;
@property (nonatomic, strong) UILabel *lblTitle;
@property (nonatomic, strong) UIButton *btnMenu;
@end
#import "ActionBar.h"
@implementation ActionBar
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self initViews];
[self initConstraints];
}
return self;
}
-(void)initViews
{
self.container = [[UIView alloc] init];
self.container.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1.0];
self.lblTitle = [[UILabel alloc] init];
self.lblTitle.textColor = [UIColor whiteColor];
self.lblTitle.text = @"Title";
self.btnMenu = [[UIButton alloc] init];
[self.btnMenu setImage:[UIImage imageNamed:@"androidMenuButton"] forState:UIControlStateNormal];
[self.container addSubview:self.lblTitle];
[self.container addSubview:self.btnMenu];
[self addSubview:self.container];
}
-(void)initConstraints
{
self.container.translatesAutoresizingMaskIntoConstraints = NO;
self.lblTitle.translatesAutoresizingMaskIntoConstraints = NO;
self.btnMenu.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{
@"container": self.container,
@"lblTitle": self.lblTitle,
@"btnMenu": self.btnMenu
};
// container constraints
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[container]|" options:0 metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[container]|" options:0 metrics:nil views:views]];
// container subview constraints
[self.container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[lblTitle]-10-[btnMenu]|" options:0 metrics:nil views:views]];
[self.container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[lblTitle]|" options:0 metrics:nil views:views]];
[self.container addConstraint:[NSLayoutConstraint constraintWithItem:self.btnMenu attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.lblTitle attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
}
@end
This custom UITableViewCell class controls the look and feel of the drop down menu cells.
#import <UIKit/UIKit.h>
@interface DropDownCell : UITableViewCell
@property (nonatomic, strong) UILabel *lblTitle;
@end
#import "DropDownCell.h"
@implementation DropDownCell
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self)
{
[self initViews];
[self initConstraints];
}
return self;
}
-(void)initViews
{
self.backgroundColor = [UIColor clearColor];
self.contentView.backgroundColor = [UIColor clearColor];
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.lblTitle = [[UILabel alloc] init];
self.lblTitle.textColor = [UIColor whiteColor];
[self.contentView addSubview:self.lblTitle];
}
-(void)initConstraints
{
self.lblTitle.translatesAutoresizingMaskIntoConstraints = NO;
id views = @{
@"lblTitle": self.lblTitle
};
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[lblTitle]|" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[lblTitle]|" options:0 metrics:nil views:views]];
}
@end
androidMenuButton@1x, @2x, @3x
I would use a Popover rather than a complete custom menu. On iPhones it is suggested to use a full screen modal presentation rather than a popover menu, but it is still possible.
This image is from the Popover documentation.
For more details on how to do it, see this answer.