仿新浪微博IOS客户端(v5.2.8)——下拉菜单栏的实现

转载请标明出处: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


今晚就到这里吧,有些累了,我先去睡了,晚安。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。