You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
393 lines
15 KiB
393 lines
15 KiB
1 year ago
|
//
|
||
|
// LMJDropdownMenu.m
|
||
|
//
|
||
|
// Created by JerryLMJ on 15/5/4.
|
||
|
// Copyright (c) 2015年 LMJ. All rights reserved.
|
||
|
//
|
||
|
|
||
|
#import "LMJDropdownMenu.h"
|
||
|
|
||
|
@interface LMJDropdownMenu() <UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate>
|
||
|
|
||
|
@property (nonatomic, strong) UIButton *mainBtn; // 菜单按钮
|
||
|
@property (nonatomic, strong) UIImageView *arrowMark; // 尖头图标
|
||
|
@property (nonatomic, strong) UITableView *optionsList; // 下拉列表
|
||
|
|
||
|
@property (nonatomic, strong) UIView *floatView;
|
||
|
@property (nonatomic, strong) UIView *coverView;
|
||
|
|
||
|
@end
|
||
|
|
||
|
|
||
|
|
||
|
@implementation LMJDropdownMenu
|
||
|
{
|
||
|
BOOL _isOpened;
|
||
|
}
|
||
|
|
||
|
- (id)initWithFrame:(CGRect)frame{
|
||
|
self = [super initWithFrame:frame];
|
||
|
if (self) {
|
||
|
[self initProperties];
|
||
|
[self initViews];
|
||
|
[self initFrame:self.frame];
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
- (void)awakeFromNib {
|
||
|
[super awakeFromNib];
|
||
|
[self initProperties];
|
||
|
[self initViews];
|
||
|
[self initFrame:self.frame];
|
||
|
}
|
||
|
|
||
|
- (void)layoutSubviews {
|
||
|
if (_isOpened) return;
|
||
|
CGFloat width = self.frame.size.width;
|
||
|
CGFloat height = self.frame.size.height;
|
||
|
[_floatView setFrame:CGRectMake(_floatView.frame.origin.x, _floatView.frame.origin.y, width, height)];
|
||
|
[_mainBtn setFrame:CGRectMake(0, 0, width, height)];
|
||
|
[_arrowMark setFrame:CGRectMake(width -self.rotateIconMarginRight -self.rotateIconSize.width, (height -self.rotateIconSize.height)/2, self.rotateIconSize.width, self.rotateIconSize.height)];
|
||
|
[_optionsList setFrame:CGRectMake(0, height, width, _optionsList.frame.size.height)];
|
||
|
}
|
||
|
|
||
|
#pragma mark - Init
|
||
|
- (void)initProperties{
|
||
|
_title = @"Please Select";
|
||
|
_titleBgColor = [UIColor colorWithRed:64/255.f green:151/255.f blue:255/255.f alpha:1];
|
||
|
_titleFont = [UIFont boldSystemFontOfSize:15];
|
||
|
_titleColor = [UIColor whiteColor];
|
||
|
_titleAlignment = NSTextAlignmentLeft;
|
||
|
_titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 10);
|
||
|
|
||
|
_rotateIcon = nil;
|
||
|
_rotateIconSize = CGSizeMake(15, 15);
|
||
|
_rotateIconMarginRight = 7.5;
|
||
|
_rotateIconTint = [UIColor blackColor];
|
||
|
|
||
|
_optionBgColor = [UIColor colorWithRed:64/255.f green:151/255.f blue:255/255.f alpha:0.5];
|
||
|
_optionFont = [UIFont systemFontOfSize:13];
|
||
|
_optionTextColor = [UIColor blackColor];
|
||
|
_optionTextAlignment = NSTextAlignmentCenter;
|
||
|
_optionTextMarginLeft = 15;
|
||
|
_optionNumberOfLines = 0;
|
||
|
_optionIconSize = CGSizeMake(0, 0);
|
||
|
_optionIconMarginRight = 15;
|
||
|
_optionLineColor = [UIColor whiteColor];
|
||
|
_optionLineHeight = 0.5f;
|
||
|
|
||
|
_animateTime = 0.25f;
|
||
|
|
||
|
_optionsListLimitHeight = 0;
|
||
|
|
||
|
_isOpened = NO;
|
||
|
}
|
||
|
|
||
|
- (void)initViews{
|
||
|
self.layer.masksToBounds = YES;
|
||
|
|
||
|
_floatView = [[UIView alloc] initWithFrame:self.bounds];
|
||
|
_floatView.layer.masksToBounds = YES;
|
||
|
[self addSubview:_floatView];
|
||
|
|
||
|
|
||
|
// 主按钮 显示在界面上的点击按钮
|
||
|
_mainBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||
|
[_mainBtn addTarget:self action:@selector(clickMainBtn:) forControlEvents:UIControlEventTouchUpInside];
|
||
|
_mainBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
|
||
|
_mainBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 15, 0, 0);
|
||
|
_mainBtn.selected = NO;
|
||
|
[_floatView addSubview:_mainBtn];
|
||
|
|
||
|
// 旋转尖头
|
||
|
_arrowMark = [[UIImageView alloc] init];
|
||
|
[_arrowMark setTintColor:self.rotateIconTint];
|
||
|
[_mainBtn addSubview:_arrowMark];
|
||
|
|
||
|
|
||
|
// 下拉列表TableView
|
||
|
_optionsList = [[UITableView alloc] init];
|
||
|
_optionsList.delegate = self;
|
||
|
_optionsList.dataSource = self;
|
||
|
_optionsList.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||
|
_optionsList.scrollEnabled = NO;
|
||
|
[_floatView addSubview:_optionsList];
|
||
|
}
|
||
|
|
||
|
- (void)initFrame:(CGRect)frame {
|
||
|
CGFloat width = frame.size.width;
|
||
|
CGFloat height = frame.size.height;
|
||
|
[_floatView setFrame:CGRectMake(0, 0, width, height)];
|
||
|
[_mainBtn setFrame:CGRectMake(0, 0, width, height)];
|
||
|
[_arrowMark setFrame:CGRectMake(width -self.rotateIconMarginRight -self.rotateIconSize.width, (height -self.rotateIconSize.height)/2, self.rotateIconSize.width, self.rotateIconSize.height)];
|
||
|
[_optionsList setFrame:CGRectMake(0, height, width, _optionsList.frame.size.height)];
|
||
|
}
|
||
|
|
||
|
#pragma mark - Action Methods
|
||
|
- (void)reloadOptionsData{
|
||
|
[self.optionsList reloadData];
|
||
|
}
|
||
|
- (void)clickMainBtn:(UIButton *)button{
|
||
|
if(button.selected == NO) {
|
||
|
[self showDropDown];
|
||
|
}else {
|
||
|
[self hideDropDown];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)showDropDown{ /* 显示下拉列表 */
|
||
|
_isOpened = YES;
|
||
|
// 变更menu图层
|
||
|
CGPoint newPosition = [self getScreenPosition];
|
||
|
_floatView.frame = CGRectMake(newPosition.x, newPosition.y, _floatView.bounds.size.width, _floatView.bounds.size.height);
|
||
|
_floatView.layer.borderColor = self.layer.borderColor;
|
||
|
_floatView.layer.borderWidth = self.layer.borderWidth;
|
||
|
_floatView.layer.cornerRadius = self.layer.cornerRadius;
|
||
|
[self.coverView addSubview:_floatView];
|
||
|
|
||
|
// call delegate
|
||
|
if ([self.delegate respondsToSelector:@selector(dropdownMenuWillShow:)]) {
|
||
|
[self.delegate dropdownMenuWillShow:self]; // 将要显示回调代理
|
||
|
}
|
||
|
|
||
|
// 刷新下拉列表数据
|
||
|
[self reloadOptionsData];
|
||
|
|
||
|
// 菜单高度计算
|
||
|
CGFloat listHeight = 0;
|
||
|
if (self.optionsListLimitHeight <= 0) { // 当未设置下拉菜单最小展示高度
|
||
|
NSUInteger count = [self.dataSource numberOfOptionsInDropdownMenu:self];
|
||
|
for (int i = 0; i < count; i++) {
|
||
|
CGFloat cHeight = [self.dataSource dropdownMenu:self heightForOptionAtIndex:i];
|
||
|
listHeight += cHeight;
|
||
|
}
|
||
|
_optionsList.scrollEnabled = NO;
|
||
|
} else {
|
||
|
listHeight = self.optionsListLimitHeight;
|
||
|
_optionsList.scrollEnabled = YES;
|
||
|
}
|
||
|
|
||
|
// 执行展开动画
|
||
|
__weak typeof(self) weakSelf = self;
|
||
|
[UIView animateWithDuration:self.animateTime animations:^{
|
||
|
UIView *floatView = weakSelf.floatView;
|
||
|
UIButton *mainBtn = weakSelf.mainBtn;
|
||
|
UITableView *listView = weakSelf.optionsList;
|
||
|
|
||
|
floatView.frame = CGRectMake(floatView.frame.origin.x, floatView.frame.origin.y, floatView.frame.size.width, mainBtn.frame.size.height + listHeight);
|
||
|
weakSelf.arrowMark.transform = CGAffineTransformMakeRotation(M_PI);
|
||
|
listView.frame = CGRectMake(listView.frame.origin.x, listView.frame.origin.y, listView.frame.size.width, listHeight);
|
||
|
|
||
|
}completion:^(BOOL finished) {
|
||
|
if ([self.delegate respondsToSelector:@selector(dropdownMenuDidShow:)]) {
|
||
|
[self.delegate dropdownMenuDidShow:self]; // 已经显示回调代理
|
||
|
}
|
||
|
}];
|
||
|
|
||
|
_mainBtn.selected = YES;
|
||
|
}
|
||
|
|
||
|
|
||
|
- (void)hideDropDown{ // 隐藏下拉列表
|
||
|
// call delegate
|
||
|
if ([self.delegate respondsToSelector:@selector(dropdownMenuWillHidden:)]) {
|
||
|
[self.delegate dropdownMenuWillHidden:self]; // 将要隐藏回调代理
|
||
|
}
|
||
|
|
||
|
// 执行关闭动画
|
||
|
__weak typeof(self) weakSelf = self;
|
||
|
[UIView animateWithDuration:self.animateTime animations:^{
|
||
|
UIView *floatView = weakSelf.floatView;
|
||
|
UIButton *mainBtn = weakSelf.mainBtn;
|
||
|
weakSelf.arrowMark.transform = CGAffineTransformIdentity;
|
||
|
weakSelf.floatView.frame = CGRectMake(floatView.frame.origin.x, floatView.frame.origin.y, floatView.frame.size.width, mainBtn.frame.size.height);
|
||
|
|
||
|
}completion:^(BOOL finished) {
|
||
|
weakSelf.optionsList.frame = CGRectMake(weakSelf.optionsList.frame.origin.x, weakSelf.optionsList.frame.origin.y, weakSelf.frame.size.width, 0);
|
||
|
|
||
|
// 变更menu图层
|
||
|
weakSelf.floatView.frame = weakSelf.floatView.bounds;
|
||
|
[self addSubview:weakSelf.floatView];
|
||
|
[weakSelf.coverView removeFromSuperview];
|
||
|
weakSelf.coverView = nil;
|
||
|
|
||
|
self->_isOpened = NO;
|
||
|
|
||
|
if ([self.delegate respondsToSelector:@selector(dropdownMenuDidHidden:)]) {
|
||
|
[self.delegate dropdownMenuDidHidden:self]; // 已经隐藏回调代理
|
||
|
}
|
||
|
}];
|
||
|
|
||
|
_mainBtn.selected = NO;
|
||
|
}
|
||
|
|
||
|
#pragma mark - Utility Methods
|
||
|
- (CGPoint)getScreenPosition {
|
||
|
return [self.superview convertPoint:self.frame.origin toView:[self getCurrentKeyWindow]];
|
||
|
}
|
||
|
|
||
|
- (UIWindow *)getCurrentKeyWindow {
|
||
|
// UIApplication * application = [UIApplication sharedApplication];
|
||
|
// if (application && application.windows && application.windows.count > 0) {
|
||
|
// return application.windows.lastObject;
|
||
|
// }
|
||
|
return [UIApplication sharedApplication].keyWindow;
|
||
|
}
|
||
|
|
||
|
#pragma mark - UITableView Delegate
|
||
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||
|
return [self.dataSource numberOfOptionsInDropdownMenu:self];
|
||
|
}
|
||
|
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||
|
return [self.dataSource dropdownMenu:self heightForOptionAtIndex:indexPath.row];
|
||
|
}
|
||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||
|
static NSString *CellIdentifier = @"MenuOptionListCell";
|
||
|
|
||
|
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
|
||
|
if (cell == nil) {
|
||
|
//---------------------------下拉选项样式,可在此处自定义-------------------------
|
||
|
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
|
||
|
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||
|
cell.backgroundColor = self.optionBgColor;
|
||
|
|
||
|
UILabel * titleLabel = [[UILabel alloc] init];
|
||
|
titleLabel.font = self.optionFont;
|
||
|
titleLabel.textColor = self.optionTextColor;
|
||
|
titleLabel.numberOfLines = self.optionNumberOfLines;
|
||
|
titleLabel.textAlignment = self.optionTextAlignment;
|
||
|
titleLabel.tag = 999;
|
||
|
[cell addSubview:titleLabel];
|
||
|
|
||
|
UIImageView * icon = [[UIImageView alloc] init];
|
||
|
icon.tag = 888;
|
||
|
[cell addSubview:icon];
|
||
|
|
||
|
UIView * line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.optionLineHeight)];
|
||
|
line.backgroundColor = self.optionLineColor;
|
||
|
line.tag = 777;
|
||
|
[cell addSubview:line];
|
||
|
//---------------------------------------------------------------------------
|
||
|
}
|
||
|
CGFloat cHeight = [self.dataSource dropdownMenu:self heightForOptionAtIndex:indexPath.row];
|
||
|
|
||
|
UILabel * titleLabel = [cell viewWithTag:999];
|
||
|
titleLabel.text = [self.dataSource dropdownMenu:self titleForOptionAtIndex:indexPath.row];;
|
||
|
titleLabel.frame = CGRectMake(self.optionTextMarginLeft, 0, self.frame.size.width - self.optionTextMarginLeft -self.optionIconSize.width -self.optionIconMarginRight, cHeight);
|
||
|
|
||
|
UIImageView * icon = [cell viewWithTag:888];
|
||
|
if ([self.dataSource respondsToSelector:@selector(dropdownMenu:iconForOptionAtIndex:)]){
|
||
|
icon.image = [self.dataSource dropdownMenu:self iconForOptionAtIndex:indexPath.row];
|
||
|
}
|
||
|
icon.frame = CGRectMake(self.frame.size.width -self.optionIconSize.width -self.optionIconMarginRight, (cHeight - self.optionIconSize.height)/2, self.optionIconSize.width, self.optionIconSize.height);
|
||
|
|
||
|
UIView *line = [cell viewWithTag:777];
|
||
|
line.frame = CGRectMake(0, 0, self.frame.size.width, self.optionLineHeight);
|
||
|
line.backgroundColor = self.optionLineColor;
|
||
|
|
||
|
return cell;
|
||
|
}
|
||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||
|
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
|
||
|
UILabel * titleLabel = [cell viewWithTag:999];
|
||
|
self.title = titleLabel.text;
|
||
|
if ([self.delegate respondsToSelector:@selector(dropdownMenu:didSelectOptionAtIndex:optionTitle:)]) {
|
||
|
[self.delegate dropdownMenu:self didSelectOptionAtIndex:indexPath.row optionTitle:titleLabel.text];
|
||
|
}
|
||
|
[self hideDropDown];
|
||
|
}
|
||
|
|
||
|
#pragma mark - UIGestureRecognizerDelegate
|
||
|
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
|
||
|
if ([NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"]) {
|
||
|
return NO;
|
||
|
}
|
||
|
return YES;
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark - Get Methods
|
||
|
- (BOOL)showsVerticalScrollIndicatorOfOptionsList {
|
||
|
return _optionsList.showsVerticalScrollIndicator;
|
||
|
}
|
||
|
|
||
|
- (UIView *)coverView {
|
||
|
UIWindow *window = [self getCurrentKeyWindow];
|
||
|
if (_coverView == nil) {
|
||
|
_coverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, window.bounds.size.width, window.bounds.size.height)];
|
||
|
_coverView.backgroundColor = [UIColor clearColor];
|
||
|
[window addSubview:_coverView];
|
||
|
|
||
|
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideDropDown)];
|
||
|
tap.delegate = self;
|
||
|
[_coverView addGestureRecognizer:tap];
|
||
|
}
|
||
|
return _coverView;
|
||
|
}
|
||
|
|
||
|
#pragma mark - Set Methods
|
||
|
- (void)setFrame:(CGRect)frame {
|
||
|
[super setFrame:frame];
|
||
|
[self initFrame:frame];
|
||
|
}
|
||
|
|
||
|
- (void)setRotateIcon:(UIImage *)rotateIcon {
|
||
|
_rotateIcon = rotateIcon;
|
||
|
[self.arrowMark setImage:rotateIcon];
|
||
|
}
|
||
|
- (void)setRotateIconSize:(CGSize)rotateIconSize {
|
||
|
_rotateIconSize = rotateIconSize;
|
||
|
[self.arrowMark setFrame:CGRectMake(self.mainBtn.bounds.size.width -self.rotateIconMarginRight -rotateIconSize.width, (self.mainBtn.bounds.size.height -rotateIconSize.height)/2, rotateIconSize.width, rotateIconSize.height)];
|
||
|
}
|
||
|
- (void)setRotateIconMarginRight:(CGFloat)rotateIconMarginRight {
|
||
|
_rotateIconMarginRight = rotateIconMarginRight;
|
||
|
[self.arrowMark setFrame:CGRectMake(self.mainBtn.bounds.size.width -rotateIconMarginRight -self.rotateIconSize.width, (self.mainBtn.bounds.size.height -self.rotateIconSize.height)/2, self.rotateIconSize.width, self.rotateIconSize.height)];
|
||
|
}
|
||
|
- (void)setRotateIconTint:(UIColor *)rotateIconTint {
|
||
|
_rotateIconTint = rotateIconTint;
|
||
|
self.arrowMark.tintColor = rotateIconTint;
|
||
|
}
|
||
|
|
||
|
- (void)setTitle:(NSString *)title{
|
||
|
_title = title;
|
||
|
[self.mainBtn setTitle:title forState:UIControlStateNormal];
|
||
|
}
|
||
|
- (void)setTitleBgColor:(UIColor *)titleBgColor{
|
||
|
_titleBgColor = titleBgColor;
|
||
|
[self.mainBtn setBackgroundColor:titleBgColor];
|
||
|
[self.arrowMark setBackgroundColor:titleBgColor];
|
||
|
}
|
||
|
- (void)setTitleFont:(UIFont *)titleFont{
|
||
|
_titleFont = titleFont;
|
||
|
self.mainBtn.titleLabel.font = titleFont;
|
||
|
}
|
||
|
- (void)setTitleColor:(UIColor *)titleColor{
|
||
|
_titleColor = titleColor;
|
||
|
[self.mainBtn setTitleColor:titleColor forState:UIControlStateNormal];
|
||
|
}
|
||
|
- (void)setTitleAlignment:(NSTextAlignment)titleAlignment{
|
||
|
_titleAlignment = titleAlignment;
|
||
|
if (titleAlignment == NSTextAlignmentLeft) {
|
||
|
self.mainBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
|
||
|
} else if (titleAlignment == NSTextAlignmentCenter) {
|
||
|
self.mainBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
|
||
|
} else if (titleAlignment == NSTextAlignmentRight) {
|
||
|
self.mainBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
|
||
|
}
|
||
|
}
|
||
|
- (void)setTitleEdgeInsets:(UIEdgeInsets)titleEdgeInsets{
|
||
|
_titleEdgeInsets = titleEdgeInsets;
|
||
|
self.mainBtn.titleEdgeInsets = titleEdgeInsets;
|
||
|
}
|
||
|
|
||
|
- (void)setShowsVerticalScrollIndicatorOfOptionsList:(BOOL)showsVerticalScrollIndicatorOfOptionsList {
|
||
|
_optionsList.showsVerticalScrollIndicator = showsVerticalScrollIndicatorOfOptionsList;
|
||
|
}
|
||
|
|
||
|
@end
|
||
|
|
||
|
|
||
|
|
||
|
|