转载请标明出处:http://blog.csdn.net/android_ls/article/details/45877983
声明:仿新浪微博项目,所用所有图片资源都来源于官方新浪微博IOS客户端,编写本应用的目的在于学习交流,如涉及侵权请告知,我会及时换掉用到的相关图片。
接着上一篇博文,这篇我们来聊聊新浪微博导航栏上,点击中间部分的标题(titleView)弹出的下拉菜单是如何实现。
1、自定义导航栏中间的titleView,代码如下:
// 设置导航栏中间的titleView
_titleButton = [self titleViewWithNickname:@"指间有梦"];
self.navigationItem.titleView = _titleButton;
2、在UIButton中默认有imageView和titleLabel两个子View,默认imageView是在左边的,而titleLabel是在右边的。我们看到在新浪微博首页上,titleView上显示的是titleLabel在左边,imageView在titleView的右边,我们试着调整UIButton中子View的显示位置,具体实现代码如下:
#pragma mark 设置导航栏中间的titleView
-(UIButton *) titleViewWithNickname:(NSString *)nickname
{
UIButton *titleButton = [[UIButton alloc] init];
// 设置图片和文字
[titleButton setTitle:nickname forState:UIControlStateNormal];
[titleButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
titleButton.titleLabel.font = [UIFont systemFontOfSize:18];
[titleButton setImage:[UIImage imageNamed:@"navigationbar_arrow_down"] forState:UIControlStateNormal];
[titleButton setImage:[UIImage imageNamed:@"navigationbar_arrow_up"] forState:UIControlStateSelected];
// 90 40这两个值目前是随便写的
titleButton.imageEdgeInsets = UIEdgeInsetsMake(0, 90, 0, 0);
titleButton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 40);
// 130这个值目前是随便写的,后面要改为根据内容自动计算长度
titleButton.size = CGSizeMake(130, 40);
// titleButton.backgroundColor = [UIColor redColor];
[titleButton addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside];
return titleButton;
}
注:不必拘于这种方式,其他方式也是可以实现(比如自定义一个View,往其中添加两个子View)。
3、调整后的效果图如下:
4、点击自定义的titleView,弹出下拉菜单,具体实现代码如下:
#pragma mark 点击导航栏上的标题事件处理器
- (void)titleClick:(UIButton *)titleButton
{
// 1.创建下拉菜单
DropdownMenuView *dropdownMenuView = [[DropdownMenuView alloc] init];
// 设置下拉菜单弹出、销毁事件的监听者
dropdownMenuView.delegate = self;
// 2.设置要显示的内容
TitleMenuViewController *titleMenuVC = [[TitleMenuViewController alloc] init];
titleMenuVC.dropdownMenuView = dropdownMenuView;
titleMenuVC.delegate = self;
titleMenuVC.view.width = kMobilePhoneScreenWidth/2;
titleMenuVC.view.height = kMobilePhoneScreenHeight/2;
dropdownMenuView.contentController = titleMenuVC;
// 3.显示下拉菜单
[dropdownMenuView showFrom:titleButton];
}
5、让当前控制器实现DropdownMenuDelegate和TitleMenuDelegate协议,实现相应的函数,具体代码如下:
@interface HomeViewController ()<DropdownMenuDelegate, TitleMenuDelegate>
{
UIButton *_titleButton;
}
@end
#pragma mark - DropdownMenuDelegate
#pragma mark 下拉菜单被销毁了
- (void)dropdownMenuDidDismiss:(DropdownMenuView *)menu
{
// 让指示箭头向下
UIButton *titleButton = (UIButton *)self.navigationItem.titleView;
titleButton.selected = NO;
}
#pragma mark 下拉菜单显示了
- (void)dropdownMenuDidShow:(DropdownMenuView *)menu
{
// 让指示箭头向上
UIButton *titleButton = (UIButton *)self.navigationItem.titleView;
titleButton.selected = YES;
}
#pragma mark - TitleMenuDelegate
-(void)selectAtIndexPath:(NSIndexPath *)indexPath title:(NSString *)title
{
MyLog(@"indexPath = %ld", indexPath.row);
MyLog(@"当前选择了%@", title);
// 修改导航栏的标题
[_titleButton setTitle:title forState:UIControlStateNormal];
// 调用根据搜索条件返回相应的微博数据
// ...
}
6、先来看看已实现的效果图,有图有真相。
点击屏幕中除下拉菜单外的任意地方,或者点击下拉菜单中的某一项(比如点击了“好友圈”),让下拉菜单销毁。
再次点击titleView,如下图:
7、下拉菜单实现核心类(DropdownMenuView.h)的源码如下:
//
// DropdownMenuView.h
// SinaWeibo
//
// Created by android_ls on 15/5/20.
// Copyright (c) 2015年 android_ls. All rights reserved.
//
// 下拉菜单组件
#import <UIKit/UIKit.h>
@class DropdownMenuView;
@protocol DropdownMenuDelegate <NSObject>
@optional
- (void)dropdownMenuDidDismiss:(DropdownMenuView *)menu;
- (void)dropdownMenuDidShow:(DropdownMenuView *)menu;
@end
@interface DropdownMenuView : UIView
@property (nonatomic, weak) id<DropdownMenuDelegate> delegate;
#pragma mark 在指定UIView下方显示菜单
- (void)showFrom:(UIView *)from;
#pragma mark 销毁下拉菜单
- (void)dismiss;
// 要显示的内容控制器
@property (nonatomic, strong) UIViewController *contentController;
@end
下拉菜单实现核心类(DropdownMenuView.m)的源码如下:
//
// DropdownMenuView.m
// SinaWeibo
//
// Created by android_ls on 15/5/20.
// Copyright (c) 2015年 android_ls. All rights reserved.
//
#import "DropdownMenuView.h"
@interface DropdownMenuView()
{
// 用来显示具体内容的容器
UIImageView * _containerView;
}
@end
@implementation DropdownMenuView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// 清除默认的背景颜色
self.backgroundColor = [UIColor clearColor];
// 添加一个灰色图片,作为下拉菜单的背景
_containerView = [[UIImageView alloc] init];
_containerView.image = [UIImage imageNamed:@"popover_background"];
_containerView.userInteractionEnabled = YES;
[self addSubview:_containerView];
}
return self;
}
- (void)setContentController:(UIViewController *)contentController
{
_contentController = contentController;
UIView * content = contentController.view;
// 调整内容的位置
content.x = 7;
content.y = 13;
_containerView.height = CGRectGetMaxY(content.frame) + 9;
_containerView.width = CGRectGetMaxX(content.frame) + 7;
// 添加内容到灰色图片中
[_containerView addSubview:content];
}
#pragma mark 在指定UIView下方显示菜单
- (void)showFrom:(UIView *)from
{
// 1.获得最上面的窗口
UIWindow *window = [[UIApplication sharedApplication].windows lastObject];
// 2.添加自己到窗口上
[window addSubview:self];
// 3.设置尺寸
self.frame = window.bounds;
// 4.调整灰色图片的位置
// 默认情况下,frame是以父控件左上角为坐标原点
// 转换坐标系
CGRect newFrame = [from convertRect:from.bounds toView:window];
_containerView.centerX = CGRectGetMidX(newFrame);
_containerView.y = CGRectGetMaxY(newFrame);
// 通知外界,自己显示了
if ([self.delegate respondsToSelector:@selector(dropdownMenuDidShow:)]) {
[self.delegate dropdownMenuDidShow:self];
}
}
#pragma mark 销毁下拉菜单
- (void)dismiss
{
[self removeFromSuperview];
// 通知外界,自己被销毁了
if ([self.delegate respondsToSelector:@selector(dropdownMenuDidDismiss:)]) {
[self.delegate dropdownMenuDidDismiss:self];
}
}
#pragma mark 点击自己执行销毁动作
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self dismiss];
}
@end
8、TitleMenuViewController.h的源码如下:
//
// TitleMenuViewController.h
// SinaWeibo
//
// Created by android_ls on 15/5/20.
// Copyright (c) 2015年 android_ls. All rights reserved.
//
#import <UIKit/UIKit.h>
@class DropdownMenuView;
@protocol TitleMenuDelegate <NSObject>
#pragma mark 当前选中了哪一行
@required
- (void)selectAtIndexPath:(NSIndexPath *)indexPath title:(NSString*)title;
@end
@interface TitleMenuViewController : UITableViewController
@property (nonatomic, weak) id<TitleMenuDelegate> delegate;
@property (nonatomic, weak) DropdownMenuView * dropdownMenuView;
@end
TitleMenuViewController.m的源码如下:
//
// TitleMenuViewController.m
// SinaWeibo
//
// Created by android_ls on 15/5/20.
// Copyright (c) 2015年 android_ls. All rights reserved.
//
#import "TitleMenuViewController.h"
#import "DropdownMenuView.h"
@interface TitleMenuViewController ()
@property (nonatomic, strong) NSMutableArray * data;
@end
@implementation TitleMenuViewController
- (void)viewDidLoad {
[super viewDidLoad];
_data = [NSMutableArray array];
[_data addObject:@"首页"];
[_data addObject:@"好友圈"];
[_data addObject:@"群微博"];
[_data addObject:@"我的微博"];
[_data addObject:@"特别关注"];
[_data addObject:@"名人明星"];
[_data addObject:@"同事"];
[_data addObject:@"同学"];
[self.tableView reloadData];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _data.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"statusCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
NSString * name = _data[indexPath.row];
cell.textLabel.text = name;
return cell;
}
#pragma mark Cell点击事件处理器
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if (_dropdownMenuView) {
[_dropdownMenuView dismiss];
}
if (_delegate) {
[_delegate selectAtIndexPath:indexPath title:_data[indexPath.row]];
}
}
@end
HomeViewController.m的完整源码如下:
//
// HomeViewController.m
// SinaWeibo
//
// Created by android_ls on 15/5/17.
// Copyright (c) 2015年 android_ls. All rights reserved.
//
// 首页动态列表控制器
#import "HomeViewController.h"
#import "UIBarButtonItem+Category.h"
#import "FriendAttentionStatusViewController.h"
#import "DropdownMenuView.h"
#import "TitleMenuViewController.h"
@interface HomeViewController ()<DropdownMenuDelegate, TitleMenuDelegate>
{
UIButton *_titleButton;
}
@end
@implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置导航栏左侧的按钮
self.navigationItem.leftBarButtonItem = [UIBarButtonItem leftBarButtonItemWithTarget:self
action:@selector(friendsearch)
image:@"navigationbar_friendsearch"
highImage:@"navigationbar_friendsearch_highlighted"];
// 设置导航栏右侧的弹出下拉菜单按钮
self.navigationItem.rightBarButtonItem = [UIBarButtonItem rightBarButtonItemWithTarget:self
action:@selector(pop)
image:@"navigationbar_pop"
highImage:@"navigationbar_pop_highlighted"];
// 设置导航栏中间的titleView
_titleButton = [self titleViewWithNickname:@"指间有梦"];
self.navigationItem.titleView = _titleButton;
}
#pragma mark 设置导航栏中间的titleView
-(UIButton *) titleViewWithNickname:(NSString *)nickname
{
UIButton *titleButton = [[UIButton alloc] init];
// 设置图片和文字
[titleButton setTitle:nickname forState:UIControlStateNormal];
[titleButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
titleButton.titleLabel.font = [UIFont systemFontOfSize:18];
[titleButton setImage:[UIImage imageNamed:@"navigationbar_arrow_down"] forState:UIControlStateNormal];
[titleButton setImage:[UIImage imageNamed:@"navigationbar_arrow_up"] forState:UIControlStateSelected];
// 90 40这两个值目前是随便写的
titleButton.imageEdgeInsets = UIEdgeInsetsMake(0, 90, 0, 0);
titleButton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 40);
// 130这个值目前是随便写的,后面要改为根据内容自动计算长度
titleButton.size = CGSizeMake(130, 40);
// titleButton.backgroundColor = [UIColor redColor];
[titleButton addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside];
return titleButton;
}
#pragma mark 点击导航栏上的标题事件处理器
- (void)titleClick:(UIButton *)titleButton
{
// 1.创建下拉菜单
DropdownMenuView *dropdownMenuView = [[DropdownMenuView alloc] init];
// 设置下拉菜单弹出、销毁事件的监听者
dropdownMenuView.delegate = self;
// 2.设置要显示的内容
TitleMenuViewController *titleMenuVC = [[TitleMenuViewController alloc] init];
titleMenuVC.dropdownMenuView = dropdownMenuView;
titleMenuVC.delegate = self;
titleMenuVC.view.width = kMobilePhoneScreenWidth/2;
titleMenuVC.view.height = kMobilePhoneScreenHeight/2;
dropdownMenuView.contentController = titleMenuVC;
// 3.显示下拉菜单
[dropdownMenuView showFrom:titleButton];
}
#pragma mark - DropdownMenuDelegate
#pragma mark 下拉菜单被销毁了
- (void)dropdownMenuDidDismiss:(DropdownMenuView *)menu
{
// 让指示箭头向下
UIButton *titleButton = (UIButton *)self.navigationItem.titleView;
titleButton.selected = NO;
}
#pragma mark 下拉菜单显示了
- (void)dropdownMenuDidShow:(DropdownMenuView *)menu
{
// 让指示箭头向上
UIButton *titleButton = (UIButton *)self.navigationItem.titleView;
titleButton.selected = YES;
}
#pragma mark - TitleMenuDelegate
-(void)selectAtIndexPath:(NSIndexPath *)indexPath title:(NSString *)title
{
MyLog(@"indexPath = %ld", indexPath.row);
MyLog(@"当前选择了%@", title);
// 修改导航栏的标题
[_titleButton setTitle:title forState:UIControlStateNormal];
// 调用根据搜索条件返回相应的微博数据
// ...
}
#pragma mark 打开好友关注动态控制器
-(void)friendsearch
{
MyLog(@"用户点击了左侧按钮");
FriendAttentionStatusViewController *friendAttentionStatusVC = [[FriendAttentionStatusViewController alloc]init];
[self.navigationController pushViewController:friendAttentionStatusVC animated:YES];
}
#pragma mark 弹出下拉菜单
-(void)pop
{
MyLog(@"用户点击了右侧弹出下拉菜单按钮");
}
@end