//
|
// JSDropDownMenu.m
|
// JSDropDownMenu
|
//
|
// Created by Jsfu on 15-1-12.
|
// Copyright (c) 2015年 jsfu. All rights reserved.
|
//
|
|
#import "JSDropDownMenu.h"
|
|
#define BackColor [UIColor colorWithRed:244.0f/255.0f green:244.0f/255.0f blue:244.0f/255.0f alpha:1.0]
|
// 选中颜色加深
|
#define SelectColor [UIColor colorWithRed:238.0f/255.0f green:238.0f/255.0f blue:238.0f/255.0f alpha:1.0]
|
|
@interface NSString (Size)
|
|
- (CGSize)textSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode;
|
|
@end
|
|
@implementation NSString (Size)
|
|
- (CGSize)textSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode
|
{
|
CGSize textSize;
|
if (CGSizeEqualToSize(size, CGSizeZero))
|
{
|
NSDictionary *attributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
|
|
textSize = [self sizeWithAttributes:attributes];
|
}
|
else
|
{
|
NSStringDrawingOptions option = NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
|
//NSStringDrawingTruncatesLastVisibleLine如果文本内容超出指定的矩形限制,文本将被截去并在最后一个字符后加上省略号。 如果指定了NSStringDrawingUsesLineFragmentOrigin选项,则该选项被忽略 NSStringDrawingUsesFontLeading计算行高时使用行间距。(字体大小+行间距=行高)
|
NSDictionary *attributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
|
CGRect rect = [self boundingRectWithSize:size
|
options:option
|
attributes:attributes
|
context:nil];
|
|
textSize = rect.size;
|
}
|
return textSize;
|
}
|
|
@end
|
|
@interface JSCollectionViewCell:UICollectionViewCell
|
|
@property(nonatomic,strong) UILabel *textLabel;
|
@property(nonatomic,strong) UIImageView *accessoryView;
|
|
-(void)removeAccessoryView;
|
|
@end
|
|
@implementation JSCollectionViewCell
|
|
-(instancetype)initWithFrame:(CGRect)frame{
|
|
self = [super initWithFrame:frame];
|
if (self) {
|
_textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
|
_textLabel.textAlignment = NSTextAlignmentCenter;
|
[self addSubview:_textLabel];
|
}
|
return self;
|
}
|
|
-(void)setAccessoryView:(UIImageView *)accessoryView{
|
|
[self removeAccessoryView];
|
|
_accessoryView = accessoryView;
|
|
_accessoryView.frame = CGRectMake(self.frame.size.width-10-16, (self.frame.size.height-12)/2, 16, 12);
|
|
[self addSubview:_accessoryView];
|
}
|
|
-(void)removeAccessoryView{
|
|
if(_accessoryView){
|
|
[_accessoryView removeFromSuperview];
|
}
|
}
|
|
@end
|
|
|
|
@interface JSTableViewCell : UITableViewCell
|
|
@property(nonatomic,readonly) UILabel *cellTextLabel;
|
@property(nonatomic,strong) UIImageView *cellAccessoryView;
|
|
-(void)setCellText:(NSString *)text align:(NSString*)align;
|
|
@end
|
|
@implementation JSTableViewCell
|
|
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
|
{
|
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
if (self) {
|
// Initialization code
|
_cellTextLabel = [[UILabel alloc] init];
|
_cellTextLabel.textAlignment = NSTextAlignmentCenter;
|
_cellTextLabel.font = [UIFont systemFontOfSize:14.0f];
|
[self addSubview:_cellTextLabel];
|
}
|
return self;
|
}
|
|
-(void)setCellText:(NSString *)text align:(NSString*)align{
|
|
_cellTextLabel.text = text;
|
// 只取宽度
|
CGSize textSize = [text textSizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(MAXFLOAT, 14) lineBreakMode:NSLineBreakByWordWrapping];
|
// CGSize textSize = [text sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(MAXFLOAT, 14)];
|
|
CGFloat marginX = 20;
|
|
if (![@"left" isEqualToString:align])
|
{
|
marginX = (self.frame.size.width-textSize.width)/2;
|
}
|
|
_cellTextLabel.frame = CGRectMake(marginX, 0, textSize.width, self.frame.size.height);
|
|
if(_cellAccessoryView){
|
_cellAccessoryView.frame = CGRectMake(_cellTextLabel.frame.origin.x+_cellTextLabel.frame.size.width+10, (self.frame.size.height-12)/2, 16, 12);
|
}
|
}
|
|
-(void)setCellAccessoryView:(UIImageView *)accessoryView{
|
|
if (_cellAccessoryView) {
|
[_cellAccessoryView removeFromSuperview];
|
}
|
|
_cellAccessoryView = accessoryView;
|
|
_cellAccessoryView.frame = CGRectMake(_cellTextLabel.frame.origin.x+_cellTextLabel.frame.size.width+10, (self.frame.size.height-12)/2, 16, 12);
|
|
[self addSubview:_cellAccessoryView];
|
}
|
|
@end
|
|
@implementation JSIndexPath
|
- (instancetype)initWithColumn:(NSInteger)column leftOrRight:(NSInteger)leftOrRight leftRow:(NSInteger)leftRow row:(NSInteger)row {
|
self = [super init];
|
if (self) {
|
_column = column;
|
_leftOrRight = leftOrRight;
|
_leftRow = leftRow;
|
_row = row;
|
}
|
return self;
|
}
|
|
+ (instancetype)indexPathWithCol:(NSInteger)col leftOrRight:(NSInteger)leftOrRight leftRow:(NSInteger)leftRow row:(NSInteger)row {
|
JSIndexPath *indexPath = [[self alloc] initWithColumn:col leftOrRight:leftOrRight leftRow:leftRow row:row];
|
return indexPath;
|
}
|
@end
|
|
#pragma mark - menu implementation
|
|
@interface JSDropDownMenu ()
|
@property (nonatomic, assign) NSInteger currentSelectedMenudIndex;
|
@property (nonatomic, assign) BOOL show;
|
@property (nonatomic, assign) NSInteger numOfMenu;
|
@property (nonatomic, assign) CGPoint origin;
|
@property (nonatomic, strong) UIView *backGroundView;
|
@property (nonatomic, strong) UIView *bottomShadow;
|
@property (nonatomic, strong) UITableView *leftTableView;
|
@property (nonatomic, strong) UITableView *rightTableView;
|
@property (nonatomic, strong) UICollectionView *collectionView;
|
//data source
|
@property (nonatomic, copy) NSArray *array;
|
//layers array
|
@property (nonatomic, copy) NSArray *titles;
|
@property (nonatomic, copy) NSArray *indicators;
|
@property (nonatomic, copy) NSArray *bgLayers;
|
@property (nonatomic, assign) NSInteger leftSelectedRow;
|
@property (nonatomic, assign) BOOL hadSelected;
|
|
@end
|
|
|
@implementation JSDropDownMenu
|
|
#pragma mark - getter
|
- (UIColor *)indicatorColor {
|
if (!_indicatorColor) {
|
_indicatorColor = [UIColor blackColor];
|
}
|
return _indicatorColor;
|
}
|
|
- (UIColor *)textColor {
|
if (!_textColor) {
|
_textColor = [UIColor blackColor];
|
}
|
return _textColor;
|
}
|
|
- (UIColor *)separatorColor {
|
if (!_separatorColor) {
|
_separatorColor = [UIColor blackColor];
|
}
|
return _separatorColor;
|
}
|
|
- (NSString *)titleForRowAtIndexPath:(JSIndexPath *)indexPath
|
{
|
return [self.dataSource menu:self titleForRowAtIndexPath:indexPath];
|
}
|
|
#pragma mark - setter
|
- (void)setDataSource:(id<JSDropDownMenuDataSource>)dataSource
|
{
|
_dataSource = dataSource;
|
|
//configure view
|
if ([_dataSource respondsToSelector:@selector(numberOfColumnsInMenu:)]) {
|
_numOfMenu = [_dataSource numberOfColumnsInMenu:self];
|
} else {
|
_numOfMenu = 1;
|
}
|
|
CGFloat textLayerInterval = self.frame.size.width / ( _numOfMenu * 2);
|
|
CGFloat separatorLineInterval = self.frame.size.width / _numOfMenu;
|
|
CGFloat bgLayerInterval = self.frame.size.width / _numOfMenu;
|
|
NSMutableArray *tempTitles = [[NSMutableArray alloc] initWithCapacity:_numOfMenu];
|
NSMutableArray *tempIndicators = [[NSMutableArray alloc] initWithCapacity:_numOfMenu];
|
NSMutableArray *tempBgLayers = [[NSMutableArray alloc] initWithCapacity:_numOfMenu];
|
|
for (int i = 0; i < _numOfMenu; i++)
|
{
|
//bgLayer
|
CGPoint bgLayerPosition = CGPointMake((i+0.5)*bgLayerInterval, self.frame.size.height/2);
|
CALayer *bgLayer = [self createBgLayerWithColor:BackColor andPosition:bgLayerPosition];
|
[self.layer addSublayer:bgLayer];
|
[tempBgLayers addObject:bgLayer];
|
//title
|
CGPoint titlePosition = CGPointMake( (i * 2 + 1) * textLayerInterval , self.frame.size.height / 2);
|
NSString *titleString = [_dataSource menu:self titleForColumn:i];
|
CATextLayer *title = [self createTextLayerWithNSString:titleString withColor:self.textColor andPosition:titlePosition];
|
[self.layer addSublayer:title];
|
[tempTitles addObject:title];
|
//indicator
|
CAShapeLayer *indicator = [self createIndicatorWithColor:self.indicatorColor andPosition:CGPointMake(titlePosition.x + title.bounds.size.width / 2 + 8, self.frame.size.height / 2)];
|
[self.layer addSublayer:indicator];
|
[tempIndicators addObject:indicator];
|
|
//separator
|
if (i != _numOfMenu - 1)
|
{
|
CGPoint separatorPosition = CGPointMake((i + 1) * separatorLineInterval, self.frame.size.height/2);
|
CAShapeLayer *separator = [self createSeparatorLineWithColor:self.separatorColor andPosition:separatorPosition];
|
[self.layer addSublayer:separator];
|
}
|
}
|
|
_bottomShadow.backgroundColor = self.separatorColor;
|
|
_titles = [tempTitles copy];
|
_indicators = [tempIndicators copy];
|
_bgLayers = [tempBgLayers copy];
|
}
|
|
#pragma mark - init method
|
|
- (instancetype)initWithOrigin:(CGPoint)origin andHeight:(CGFloat)height{
|
CGSize screenSize = [UIScreen mainScreen].bounds.size;
|
self = [self initWithFrame:CGRectMake(origin.x, origin.y, screenSize.width, height)];
|
if (self) {
|
_origin = origin;
|
_currentSelectedMenudIndex = -1;
|
_show = NO;
|
|
_hadSelected = NO;
|
|
//tableView init
|
_leftTableView = [[UITableView alloc] initWithFrame:CGRectMake(origin.x, self.frame.origin.y + self.frame.size.height, 0, 0) style:UITableViewStyleGrouped];
|
_leftTableView.rowHeight = 38;
|
_leftTableView.separatorColor = [UIColor colorWithRed:220.f/255.0f green:220.f/255.0f blue:220.f/255.0f alpha:1.0];
|
_leftTableView.dataSource = self;
|
_leftTableView.delegate = self;
|
_leftTableView.hidden = NO;
|
|
_rightTableView = [[UITableView alloc] initWithFrame:CGRectMake(self.frame.size.width, self.frame.origin.y + self.frame.size.height, 0, 0) style:UITableViewStyleGrouped];
|
_rightTableView.rowHeight = 38;
|
_rightTableView.separatorColor = [UIColor colorWithRed:220.f/255.0f green:220.f/255.0f blue:220.f/255.0f alpha:1.0];
|
_rightTableView.dataSource = self;
|
_rightTableView.delegate = self;
|
_rightTableView.hidden = NO;
|
|
UICollectionViewFlowLayout *flowLayout=[[UICollectionViewFlowLayout alloc] init];
|
flowLayout.minimumInteritemSpacing = 0;
|
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(origin.x, self.frame.origin.y + self.frame.size.height, self.frame.size.width, 0) collectionViewLayout:flowLayout];
|
|
[_collectionView registerClass:[JSCollectionViewCell class] forCellWithReuseIdentifier:@"CollectionCell"];
|
_collectionView.backgroundColor = [UIColor colorWithRed:220.f/255.0f green:220.f/255.0f blue:220.f/255.0f alpha:1.0];
|
_collectionView.dataSource = self;
|
_collectionView.delegate = self;
|
|
|
self.autoresizesSubviews = NO;
|
_leftTableView.autoresizesSubviews = NO;
|
_rightTableView.autoresizesSubviews = NO;
|
_collectionView.autoresizesSubviews = NO;
|
|
//self tapped
|
self.backgroundColor = [UIColor whiteColor];
|
UIGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(menuTapped:)];
|
[self addGestureRecognizer:tapGesture];
|
|
//background init and tapped
|
_backGroundView = [[UIView alloc] initWithFrame:CGRectMake(origin.x, origin.y, screenSize.width, screenSize.height)];
|
_backGroundView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.0];
|
_backGroundView.opaque = NO;
|
UIGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(backgroundTapped:)];
|
[_backGroundView addGestureRecognizer:gesture];
|
|
//add bottom shadow
|
_bottomShadow = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height-0.5, screenSize.width, 0.5)];
|
[self addSubview:_bottomShadow];
|
}
|
return self;
|
}
|
|
#pragma mark - init support
|
- (CALayer *)createBgLayerWithColor:(UIColor *)color andPosition:(CGPoint)position {
|
CALayer *layer = [CALayer layer];
|
|
layer.position = position;
|
layer.bounds = CGRectMake(0, 0, self.frame.size.width/self.numOfMenu, self.frame.size.height-1);
|
layer.backgroundColor = color.CGColor;
|
|
return layer;
|
}
|
|
- (CAShapeLayer *)createIndicatorWithColor:(UIColor *)color andPosition:(CGPoint)point {
|
CAShapeLayer *layer = [CAShapeLayer new];
|
|
UIBezierPath *path = [UIBezierPath new];
|
[path moveToPoint:CGPointMake(0, 0)];
|
[path addLineToPoint:CGPointMake(8, 0)];
|
[path addLineToPoint:CGPointMake(4, 5)];
|
[path closePath];
|
|
layer.path = path.CGPath;
|
layer.lineWidth = 1.0;
|
layer.fillColor = color.CGColor;
|
|
CGPathRef bound = CGPathCreateCopyByStrokingPath(layer.path, nil, layer.lineWidth, kCGLineCapButt, kCGLineJoinMiter, layer.miterLimit);
|
layer.bounds = CGPathGetBoundingBox(bound);
|
|
CGPathRelease(bound);
|
|
layer.position = point;
|
|
return layer;
|
}
|
|
- (CAShapeLayer *)createSeparatorLineWithColor:(UIColor *)color andPosition:(CGPoint)point {
|
CAShapeLayer *layer = [CAShapeLayer new];
|
|
UIBezierPath *path = [UIBezierPath new];
|
[path moveToPoint:CGPointMake(160,0)];
|
[path addLineToPoint:CGPointMake(160, self.frame.size.height)];
|
|
layer.path = path.CGPath;
|
layer.lineWidth = 1.0;
|
layer.strokeColor = color.CGColor;
|
|
CGPathRef bound = CGPathCreateCopyByStrokingPath(layer.path, nil, layer.lineWidth, kCGLineCapButt, kCGLineJoinMiter, layer.miterLimit);
|
layer.bounds = CGPathGetBoundingBox(bound);
|
|
CGPathRelease(bound);
|
|
layer.position = point;
|
|
return layer;
|
}
|
|
- (CATextLayer *)createTextLayerWithNSString:(NSString *)string withColor:(UIColor *)color andPosition:(CGPoint)point {
|
|
CGSize size = [self calculateTitleSizeWithString:string];
|
|
CATextLayer *layer = [CATextLayer new];
|
CGFloat sizeWidth = (size.width < (self.frame.size.width / _numOfMenu) - 25) ? size.width : self.frame.size.width / _numOfMenu - 25;
|
layer.bounds = CGRectMake(0, 0, sizeWidth, size.height);
|
layer.string = string;
|
layer.fontSize = 14.0;
|
layer.alignmentMode = kCAAlignmentCenter;
|
layer.foregroundColor = color.CGColor;
|
|
layer.contentsScale = [[UIScreen mainScreen] scale];
|
|
layer.position = point;
|
|
return layer;
|
}
|
|
- (CGSize)calculateTitleSizeWithString:(NSString *)string
|
{
|
CGFloat fontSize = 14.0;
|
NSDictionary *dic = @{NSFontAttributeName: [UIFont systemFontOfSize:fontSize]};
|
CGSize size = [string boundingRectWithSize:CGSizeMake(280, 0) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:dic context:nil].size;
|
return size;
|
}
|
|
#pragma mark - gesture handle
|
- (void)menuTapped:(UITapGestureRecognizer *)paramSender
|
{
|
CGPoint touchPoint = [paramSender locationInView:self];
|
//calculate index
|
NSInteger tapIndex = touchPoint.x / (self.frame.size.width / _numOfMenu);
|
|
for (int i = 0; i < _numOfMenu; i++)
|
{
|
if (i != tapIndex)
|
{
|
[self animateIndicator:_indicators[i] Forward:NO complete:^{
|
[self animateTitle:_titles[i] show:NO complete:^{
|
|
}];
|
}];
|
|
[(CALayer *)self.bgLayers[i] setBackgroundColor:BackColor.CGColor];
|
}
|
}
|
|
BOOL displayByCollectionView = NO;
|
|
if ([_dataSource respondsToSelector:@selector(displayByCollectionViewInColumn:)]) {
|
|
displayByCollectionView = [_dataSource displayByCollectionViewInColumn:tapIndex];
|
}
|
|
if (displayByCollectionView)
|
{
|
UICollectionView *collectionView = _collectionView;
|
|
if (tapIndex == _currentSelectedMenudIndex && _show)
|
{
|
[self animateIdicator:_indicators[_currentSelectedMenudIndex] background:_backGroundView collectionView:collectionView title:_titles[_currentSelectedMenudIndex] forward:NO complecte:^{
|
_currentSelectedMenudIndex = tapIndex;
|
_show = NO;
|
}];
|
|
[(CALayer *)self.bgLayers[tapIndex] setBackgroundColor:BackColor.CGColor];
|
}
|
else
|
{
|
_currentSelectedMenudIndex = tapIndex;
|
[_collectionView reloadData];
|
if (_currentSelectedMenudIndex!=-1)
|
{
|
// 需要隐藏tableview
|
[self animateLeftTableView:_leftTableView rightTableView:_rightTableView show:NO complete:^{
|
|
[self animateIdicator:_indicators[tapIndex] background:_backGroundView collectionView:collectionView title:_titles[tapIndex] forward:YES complecte:^{
|
_show = YES;
|
}];
|
}];
|
}
|
else
|
{
|
[self animateIdicator:_indicators[tapIndex] background:_backGroundView collectionView:collectionView title:_titles[tapIndex] forward:YES complecte:^{
|
_show = YES;
|
}];
|
}
|
[(CALayer *)self.bgLayers[tapIndex] setBackgroundColor:SelectColor.CGColor];
|
}
|
}
|
else
|
{
|
BOOL haveRightTableView = [_dataSource haveRightTableViewInColumn:tapIndex];
|
// UITableView *leftTableView = _leftTableView;
|
UITableView *rightTableView = nil;
|
|
if (haveRightTableView)
|
{
|
rightTableView = _rightTableView;
|
// 修改左右tableview显示比例
|
}
|
|
if (tapIndex == _currentSelectedMenudIndex && _show)
|
{
|
|
[self animateIdicator:_indicators[_currentSelectedMenudIndex] background:_backGroundView leftTableView:_leftTableView rightTableView:_rightTableView title:_titles[_currentSelectedMenudIndex] forward:NO complecte:^{
|
_currentSelectedMenudIndex = tapIndex;
|
_show = NO;
|
}];
|
|
[(CALayer *)self.bgLayers[tapIndex] setBackgroundColor:BackColor.CGColor];
|
}
|
else
|
{
|
|
_hadSelected = NO;
|
|
_currentSelectedMenudIndex = tapIndex;
|
|
if ([_dataSource respondsToSelector:@selector(currentLeftSelectedRow:)]) {
|
|
_leftSelectedRow = [_dataSource currentLeftSelectedRow:_currentSelectedMenudIndex];
|
}
|
|
if (rightTableView)
|
{
|
[rightTableView reloadData];
|
}
|
|
[_leftTableView reloadData];
|
|
CGFloat ratio = [_dataSource widthRatioOfLeftColumn:_currentSelectedMenudIndex];
|
if (_leftTableView)
|
{
|
_leftTableView.frame = CGRectMake(_leftTableView.frame.origin.x, self.frame.origin.y + self.frame.size.height, self.frame.size.width*ratio, 0);
|
}
|
|
if (_rightTableView)
|
{
|
_rightTableView.frame = CGRectMake(_origin.x+_leftTableView.frame.size.width, self.frame.origin.y + self.frame.size.height, self.frame.size.width*(1-ratio), 0);
|
}
|
|
if (_currentSelectedMenudIndex!=-1)
|
{
|
// 需要隐藏collectionview
|
[self animateCollectionView:_collectionView show:NO complete:^{
|
|
[self animateIdicator:_indicators[tapIndex] background:_backGroundView leftTableView:_leftTableView rightTableView:_rightTableView title:_titles[tapIndex] forward:YES complecte:^{
|
_show = YES;
|
}];
|
}];
|
|
}
|
else
|
{
|
[self animateIdicator:_indicators[tapIndex] background:_backGroundView leftTableView:_leftTableView rightTableView:_rightTableView title:_titles[tapIndex] forward:YES complecte:^{
|
_show = YES;
|
}];
|
}
|
|
[(CALayer *)self.bgLayers[tapIndex] setBackgroundColor:SelectColor.CGColor];
|
}
|
}
|
}
|
|
- (void)backgroundTapped:(UITapGestureRecognizer *)paramSender
|
{
|
BOOL displayByCollectionView = NO;
|
|
if ([_dataSource respondsToSelector:@selector(displayByCollectionViewInColumn:)])
|
{
|
|
displayByCollectionView = [_dataSource displayByCollectionViewInColumn:_currentSelectedMenudIndex];
|
}
|
|
if (displayByCollectionView)
|
{
|
[self animateIdicator:_indicators[_currentSelectedMenudIndex] background:_backGroundView collectionView:_collectionView title:_titles[_currentSelectedMenudIndex] forward:NO complecte:^{
|
_show = NO;
|
}];
|
|
}
|
else
|
{
|
[self animateIdicator:_indicators[_currentSelectedMenudIndex] background:_backGroundView leftTableView:_leftTableView rightTableView:_rightTableView title:_titles[_currentSelectedMenudIndex] forward:NO complecte:^{
|
_show = NO;
|
}];
|
}
|
|
[(CALayer *)self.bgLayers[_currentSelectedMenudIndex] setBackgroundColor:BackColor.CGColor];
|
}
|
|
#pragma mark - animation method
|
- (void)animateIndicator:(CAShapeLayer *)indicator Forward:(BOOL)forward complete:(void(^)())complete {
|
[CATransaction begin];
|
[CATransaction setAnimationDuration:0.25];
|
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithControlPoints:0.4 :0.0 :0.2 :1.0]];
|
|
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
|
anim.values = forward ? @[ @0, @(M_PI) ] : @[ @(M_PI), @0 ];
|
|
if (!anim.removedOnCompletion) {
|
[indicator addAnimation:anim forKey:anim.keyPath];
|
} else {
|
[indicator addAnimation:anim forKey:anim.keyPath];
|
[indicator setValue:anim.values.lastObject forKeyPath:anim.keyPath];
|
}
|
|
[CATransaction commit];
|
|
complete();
|
}
|
|
- (void)animateBackGroundView:(UIView *)view show:(BOOL)show complete:(void(^)())complete {
|
if (show) {
|
[self.superview addSubview:view];
|
[view.superview addSubview:self];
|
|
[UIView animateWithDuration:0.2 animations:^{
|
view.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.3];
|
}];
|
} else {
|
[UIView animateWithDuration:0.2 animations:^{
|
view.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.0];
|
} completion:^(BOOL finished) {
|
[view removeFromSuperview];
|
}];
|
}
|
complete();
|
}
|
|
/**
|
*动画显示下拉菜单
|
*/
|
- (void)animateLeftTableView:(UITableView *)leftTableView rightTableView:(UITableView *)rightTableView show:(BOOL)show complete:(void(^)())complete {
|
|
CGFloat ratio = [_dataSource widthRatioOfLeftColumn:_currentSelectedMenudIndex];
|
|
if (show) {
|
|
CGFloat leftTableViewHeight = 0;
|
|
CGFloat rightTableViewHeight = 0;
|
|
if (leftTableView)
|
{
|
|
leftTableView.frame = CGRectMake(_origin.x, self.frame.origin.y + self.frame.size.height, self.frame.size.width*ratio, 0);
|
[self.superview addSubview:leftTableView];
|
|
leftTableViewHeight = ([leftTableView numberOfRowsInSection:0] > 5) ? (5 * leftTableView.rowHeight) : ([leftTableView numberOfRowsInSection:0] * leftTableView.rowHeight);
|
|
}
|
|
if (rightTableView)
|
{
|
|
rightTableView.frame = CGRectMake(_origin.x+leftTableView.frame.size.width, self.frame.origin.y + self.frame.size.height, self.frame.size.width*(1-ratio), 0);
|
|
[self.superview addSubview:rightTableView];
|
|
rightTableViewHeight = ([rightTableView numberOfRowsInSection:0] > 5) ? (5 * rightTableView.rowHeight) : ([rightTableView numberOfRowsInSection:0] * rightTableView.rowHeight);
|
}
|
|
CGFloat tableViewHeight = MAX(leftTableViewHeight, rightTableViewHeight);
|
|
[UIView animateWithDuration:0.2 animations:^{
|
if (leftTableView) {
|
leftTableView.frame = CGRectMake(_origin.x, self.frame.origin.y + self.frame.size.height, self.frame.size.width*ratio, tableViewHeight);
|
}
|
if (rightTableView) {
|
rightTableView.frame = CGRectMake(_origin.x+leftTableView.frame.size.width, self.frame.origin.y + self.frame.size.height, self.frame.size.width*(1-ratio), tableViewHeight);
|
}
|
}];
|
} else {
|
[UIView animateWithDuration:0.2 animations:^{
|
|
if (leftTableView) {
|
leftTableView.frame = CGRectMake(_origin.x, self.frame.origin.y + self.frame.size.height, self.frame.size.width*ratio, 0);
|
}
|
if (rightTableView) {
|
rightTableView.frame = CGRectMake(_origin.x+leftTableView.frame.size.width, self.frame.origin.y + self.frame.size.height, self.frame.size.width*(1-ratio), 0);
|
}
|
|
} completion:^(BOOL finished) {
|
|
if (leftTableView) {
|
[leftTableView removeFromSuperview];
|
}
|
if (rightTableView) {
|
[rightTableView removeFromSuperview];
|
}
|
}];
|
}
|
complete();
|
}
|
|
/**
|
*动画显示下拉菜单
|
*/
|
- (void)animateCollectionView:(UICollectionView *)collectionView show:(BOOL)show complete:(void(^)())complete {
|
|
if (show) {
|
|
CGFloat collectionViewHeight = 0;
|
|
if (collectionView) {
|
|
collectionView.frame = CGRectMake(_origin.x, self.frame.origin.y + self.frame.size.height, self.frame.size.width, 0);
|
[self.superview addSubview:collectionView];
|
|
collectionViewHeight = ([collectionView numberOfItemsInSection:0] > 10) ? (5 * 38) : (ceil([collectionView numberOfItemsInSection:0]/2) * 38);
|
}
|
|
[UIView animateWithDuration:0.2 animations:^{
|
if (collectionView) {
|
collectionView.frame = CGRectMake(_origin.x, self.frame.origin.y + self.frame.size.height, self.frame.size.width, collectionViewHeight);
|
}
|
}];
|
} else {
|
[UIView animateWithDuration:0.2 animations:^{
|
|
if (collectionView) {
|
collectionView.frame = CGRectMake(_origin.x, self.frame.origin.y + self.frame.size.height, self.frame.size.width, 0);
|
}
|
} completion:^(BOOL finished) {
|
|
if (collectionView) {
|
[collectionView removeFromSuperview];
|
}
|
}];
|
}
|
complete();
|
}
|
|
- (void)animateTitle:(CATextLayer *)title show:(BOOL)show complete:(void(^)())complete {
|
CGSize size = [self calculateTitleSizeWithString:title.string];
|
CGFloat sizeWidth = (size.width < (self.frame.size.width / _numOfMenu) - 25) ? size.width : self.frame.size.width / _numOfMenu - 25;
|
title.bounds = CGRectMake(0, 0, sizeWidth, size.height);
|
complete();
|
}
|
|
- (void)animateIdicator:(CAShapeLayer *)indicator background:(UIView *)background leftTableView:(UITableView *)leftTableView rightTableView:(UITableView *)rightTableView title:(CATextLayer *)title forward:(BOOL)forward complecte:(void(^)())complete{
|
|
[self animateIndicator:indicator Forward:forward complete:^{
|
[self animateTitle:title show:forward complete:^{
|
[self animateBackGroundView:background show:forward complete:^{
|
[self animateLeftTableView:leftTableView rightTableView:rightTableView show:forward complete:^{
|
}];
|
}];
|
}];
|
}];
|
|
complete();
|
}
|
|
- (void)animateIdicator:(CAShapeLayer *)indicator background:(UIView *)background collectionView:(UICollectionView *)collectionView title:(CATextLayer *)title forward:(BOOL)forward complecte:(void(^)())complete{
|
|
[self animateIndicator:indicator Forward:forward complete:^{
|
[self animateTitle:title show:forward complete:^{
|
[self animateBackGroundView:background show:forward complete:^{
|
[self animateCollectionView:collectionView show:forward complete:^{
|
|
}];
|
|
}];
|
}];
|
}];
|
|
complete();
|
}
|
|
#pragma mark - table datasource
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
|
NSInteger leftOrRight = 0;
|
if (_rightTableView==tableView) {
|
leftOrRight = 1;
|
}
|
|
NSAssert(self.dataSource != nil, @"menu's dataSource shouldn't be nil");
|
if ([self.dataSource respondsToSelector:@selector(menu:numberOfRowsInColumn:leftOrRight: leftRow:)]) {
|
return [self.dataSource menu:self numberOfRowsInColumn:self.currentSelectedMenudIndex leftOrRight:leftOrRight leftRow:_leftSelectedRow];
|
} else {
|
NSAssert(0 == 1, @"required method of dataSource protocol should be implemented");
|
return 0;
|
}
|
}
|
|
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
|
return 0.1;
|
}
|
|
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
|
return 0.1;
|
}
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
{
|
static NSString *identifier = @"DropDownMenuCell";
|
|
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
|
|
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.frame];
|
cell.selectedBackgroundView.backgroundColor = BackColor;
|
|
UILabel *titleLabel = [[UILabel alloc] init];
|
titleLabel.textColor = self.textColor;
|
titleLabel.tag = 1;
|
titleLabel.font = [UIFont systemFontOfSize:14.0];
|
|
[cell addSubview:titleLabel];
|
|
|
NSInteger leftOrRight = 0;
|
|
if (_rightTableView==tableView)
|
{
|
|
leftOrRight = 1;
|
}
|
|
// UILabel *titleLabel = (UILabel*)[cell viewWithTag:1];
|
|
CGSize textSize;
|
|
if ([self.dataSource respondsToSelector:@selector(menu:titleForRowAtIndexPath:)])
|
{
|
|
titleLabel.text = [self.dataSource menu:self titleForRowAtIndexPath:[JSIndexPath indexPathWithCol:self.currentSelectedMenudIndex leftOrRight:leftOrRight leftRow:_leftSelectedRow row:indexPath.row]];
|
// 只取宽度
|
textSize = [titleLabel.text textSizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(MAXFLOAT, 14) lineBreakMode:NSLineBreakByWordWrapping];
|
|
}
|
|
cell.backgroundColor = [UIColor whiteColor];
|
cell.textLabel.font = [UIFont systemFontOfSize:14.0];
|
cell.separatorInset = UIEdgeInsetsZero;
|
|
|
if (leftOrRight == 1)
|
{
|
|
CGFloat marginX = 20;
|
|
titleLabel.frame = CGRectMake(marginX, 0, textSize.width, cell.frame.size.height);
|
//右边tableview
|
cell.backgroundColor = BackColor;
|
|
if ([titleLabel.text isEqualToString:[(CATextLayer *)[_titles objectAtIndex:_currentSelectedMenudIndex] string]]) {
|
|
UIImageView *accessoryImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ico_make"]];
|
|
accessoryImageView.frame = CGRectMake(titleLabel.frame.origin.x+titleLabel.frame.size.width+10, (self.frame.size.height-12)/2, 16, 12);
|
|
[cell addSubview:accessoryImageView];
|
} else{
|
|
|
}
|
}
|
else
|
{
|
|
CGFloat ratio = [_dataSource widthRatioOfLeftColumn:_currentSelectedMenudIndex];
|
|
CGFloat marginX = (self.frame.size.width*ratio-textSize.width)/2;
|
|
titleLabel.frame = CGRectMake(marginX, 0, textSize.width, cell.frame.size.height);
|
|
if (!_hadSelected && _leftSelectedRow == indexPath.row)
|
{
|
cell.backgroundColor = BackColor;
|
BOOL haveRightTableView = [_dataSource haveRightTableViewInColumn:_currentSelectedMenudIndex];
|
if(!haveRightTableView){
|
UIImageView *accessoryImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ico_make"]];
|
|
accessoryImageView.frame = CGRectMake(titleLabel.frame.origin.x+titleLabel.frame.size.width+10, (self.frame.size.height-12)/2, 16, 12);
|
|
[cell addSubview:accessoryImageView];
|
}
|
} else{
|
|
}
|
}
|
|
return cell;
|
}
|
|
#pragma mark - tableview delegate
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
NSInteger leftOrRight = 0;
|
if (_rightTableView==tableView) {
|
leftOrRight = 1;
|
} else {
|
_leftSelectedRow = indexPath.row;
|
}
|
|
if (self.delegate || [self.delegate respondsToSelector:@selector(menu:didSelectRowAtIndexPath:)]) {
|
|
BOOL haveRightTableView = [_dataSource haveRightTableViewInColumn:_currentSelectedMenudIndex];
|
|
if ((leftOrRight==0 && !haveRightTableView) || leftOrRight==1) {
|
[self confiMenuWithSelectRow:indexPath.row leftOrRight:leftOrRight];
|
}
|
|
[self.delegate menu:self didSelectRowAtIndexPath:[JSIndexPath indexPathWithCol:self.currentSelectedMenudIndex leftOrRight:leftOrRight leftRow:_leftSelectedRow row:indexPath.row]];
|
|
if (leftOrRight==0 && haveRightTableView) {
|
if (!_hadSelected) {
|
_hadSelected = YES;
|
[_leftTableView reloadData];
|
NSIndexPath *selectedIndexPath = [NSIndexPath indexPathForRow:_leftSelectedRow inSection:0];
|
|
[_leftTableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
|
}
|
|
[_rightTableView reloadData];
|
}
|
|
} else {
|
//TODO: delegate is nil
|
}
|
}
|
|
- (void)confiMenuWithSelectRow:(NSInteger)row leftOrRight:(NSInteger)leftOrRight{
|
CATextLayer *title = (CATextLayer *)_titles[_currentSelectedMenudIndex];
|
title.string = [self.dataSource menu:self titleForRowAtIndexPath:[JSIndexPath indexPathWithCol:self.currentSelectedMenudIndex leftOrRight:leftOrRight leftRow:_leftSelectedRow row:row]];
|
|
[self animateIdicator:_indicators[_currentSelectedMenudIndex] background:_backGroundView leftTableView:_leftTableView rightTableView:_rightTableView title:_titles[_currentSelectedMenudIndex] forward:NO complecte:^{
|
_show = NO;
|
}];
|
[(CALayer *)self.bgLayers[_currentSelectedMenudIndex] setBackgroundColor:BackColor.CGColor];
|
|
CAShapeLayer *indicator = (CAShapeLayer *)_indicators[_currentSelectedMenudIndex];
|
indicator.position = CGPointMake(title.position.x + title.frame.size.width / 2 + 8, indicator.position.y);
|
}
|
|
#pragma mark - UICollectionViewDataSource
|
|
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
|
return 1;
|
}
|
|
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
|
|
// 为collectionview时 leftOrRight 为-1
|
if ([self.dataSource respondsToSelector:@selector(menu:numberOfRowsInColumn:leftOrRight: leftRow:)]) {
|
return [self.dataSource menu:self numberOfRowsInColumn:self.currentSelectedMenudIndex leftOrRight:-1 leftRow:-1];
|
} else {
|
NSAssert(0 == 1, @"required method of dataSource protocol should be implemented");
|
return 0;
|
}
|
}
|
|
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
|
|
static NSString *collectionCell = @"CollectionCell";
|
JSCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:collectionCell forIndexPath:indexPath];
|
|
if ([self.dataSource respondsToSelector:@selector(menu:titleForRowAtIndexPath:)])
|
{
|
cell.textLabel.text = [self.dataSource menu:self titleForRowAtIndexPath:[JSIndexPath indexPathWithCol:self.currentSelectedMenudIndex leftOrRight:-1 leftRow:-1 row:indexPath.row]];
|
}
|
else
|
{
|
NSAssert(0 == 1, @"dataSource method needs to be implemented");
|
}
|
|
cell.backgroundColor = [UIColor whiteColor];
|
cell.selectedBackgroundView.backgroundColor = BackColor;
|
cell.textLabel.font = [UIFont systemFontOfSize:14.0];
|
cell.textLabel.textColor = self.textColor;
|
|
if ([cell.textLabel.text isEqualToString:[(CATextLayer *)[_titles objectAtIndex:_currentSelectedMenudIndex] string]])
|
{
|
cell.backgroundColor = BackColor;
|
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ico_make"]];
|
}
|
else
|
{
|
[cell removeAccessoryView];
|
}
|
|
return cell;
|
}
|
|
#pragma mark --UICollectionViewDelegateFlowLayout
|
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
{
|
return CGSizeMake((collectionView.frame.size.width-1)/2, 38);
|
}
|
|
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
|
{
|
return UIEdgeInsetsMake(0, 0, 1, 0.5);
|
}
|
|
#pragma mark --UICollectionViewDelegate
|
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
|
{
|
if (self.delegate || [self.delegate respondsToSelector:@selector(menu:didSelectRowAtIndexPath:)])
|
{
|
[self confiMenuWithSelectRow:indexPath.row];
|
|
[self.delegate menu:self didSelectRowAtIndexPath:[JSIndexPath indexPathWithCol:self.currentSelectedMenudIndex leftOrRight:-1 leftRow:-1 row:indexPath.row]];
|
} else {
|
//TODO: delegate is nil
|
}
|
}
|
|
- (void)confiMenuWithSelectRow:(NSInteger)row{
|
CATextLayer *title = (CATextLayer *)_titles[_currentSelectedMenudIndex];
|
title.string = [self.dataSource menu:self titleForRowAtIndexPath:[JSIndexPath indexPathWithCol:self.currentSelectedMenudIndex leftOrRight:-1 leftRow:-1 row:row]];
|
|
[self animateIdicator:_indicators[_currentSelectedMenudIndex] background:_backGroundView collectionView:_collectionView title:_titles[_currentSelectedMenudIndex] forward:NO complecte:^{
|
_show = NO;
|
}];
|
|
[(CALayer *)self.bgLayers[_currentSelectedMenudIndex] setBackgroundColor:BackColor.CGColor];
|
|
CAShapeLayer *indicator = (CAShapeLayer *)_indicators[_currentSelectedMenudIndex];
|
indicator.position = CGPointMake(title.position.x + title.frame.size.width / 2 + 8, indicator.position.y);
|
}
|
|
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section{
|
|
return 0.5;
|
}
|
|
@end
|