ZJQBOSwipeMenuOption.h
//
// ZJQBOSwipeMenuOption.h
// demo010
//
// Created by zhoujianqiang on 15/9/26.
// Copyright © 2015年 zhoujianqiang. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ZJQBOSwipeMenuOption : NSObject
@property (nonatomic,assign) CGRect frame;//菜单区视图的frame属性
@property (nonatomic,strong) UIColor* selectedTextColor;//菜单被选中时的文字颜色
@property (nonatomic,strong) UIColor* unselectedTextColor;//菜单未选中时的文字颜色
@property (nonatomic,strong) UIColor* selectedTextBackground;//菜单被选中时的文字背景颜色
@property (nonatomic,strong) UIColor* unselectedTextBackground;//菜单未选中时的文字背景颜色
@property (nonatomic,strong) UIFont* textFont;//菜单字体大小
@property (nonatomic,strong) UIImage* selectedLineImage;//菜单被选中时底线颜色图片
@property (nonatomic,strong) UIImage* unselectedLineImage;//菜单未选中时底线颜色图片
@property (nonatomic,assign) CGFloat lineImageHeight;//菜单底线图片的高度
@property (nonatomic,assign) NSInteger max;//菜单数量显示上限,超过max数量的菜单必须通过左右滑动手势显示
#pragma mark 对象初始化-对象方法
-(instancetype)initWithFrame : (CGRect) frame
andWithSelectedTextColor : (UIColor*) selectedTextColor
andWithUnselectedTextColor : (UIColor*) unselectedTextColor
andWithSelectedTextBackground : (UIColor*) selectedTextBackground
andWithUnselectedTextBackground : (UIColor*) unselectedTextBackground
andWithTextFont : (UIFont*) textFont
andWithSelectedLineImage : (UIImage*) selectedLineImage
andWithUnselectedLineImage : (UIImage*) unselectedLineImage
andWithLineImageHeight : (CGFloat) lineImageHeight
andWithMax : (NSInteger) max;
#pragma mark 对象初始化-类方法
+(instancetype)initWithFrame : (CGRect) frame
andWithSelectedTextColor : (UIColor*) selectedTextColor
andWithUnselectedTextColor : (UIColor*) unselectedTextColor
andWithSelectedTextBackground : (UIColor*) selectedTextBackground
andWithUnselectedTextBackground : (UIColor*) unselectedTextBackground
andWithTextFont : (UIFont*) textFont
andWithSelectedLineImage : (UIImage*) selectedLineImage
andWithUnselectedLineImage : (UIImage*) unselectedLineImage
andWithLineImageHeight : (CGFloat) lineImageHeight
andWithMax : (NSInteger) max;
@end
ZJQBOSwipeMenuOption.m
//
// ZJQBOSwipeMenuOption.m
// demo010
//
// Created by zhoujianqiang on 15/9/26.
// Copyright © 2015年 zhoujianqiang. All rights reserved.
//
#import "ZJQBOSwipeMenuOption.h"
@implementation ZJQBOSwipeMenuOption
#pragma mark 对象初始化-对象方法
-(instancetype)initWithFrame : (CGRect) frame
andWithSelectedTextColor : (UIColor*) selectedTextColor
andWithUnselectedTextColor : (UIColor*) unselectedTextColor
andWithSelectedTextBackground : (UIColor*) selectedTextBackground
andWithUnselectedTextBackground : (UIColor*) unselectedTextBackground
andWithTextFont : (UIFont*) textFont
andWithSelectedLineImage : (UIImage*) selectedLineImage
andWithUnselectedLineImage : (UIImage*) unselectedLineImage
andWithLineImageHeight : (CGFloat) lineImageHeight
andWithMax : (NSInteger) max
{
if (self=[super init]) {
_frame=frame;
_selectedTextColor=selectedTextColor;
_unselectedTextColor=unselectedTextColor;
_selectedTextBackground=selectedTextBackground;
_unselectedTextBackground=unselectedTextBackground;
_textFont=textFont;
_selectedLineImage=selectedLineImage;
_unselectedLineImage=unselectedLineImage;
_lineImageHeight=lineImageHeight;
_max=max;
}
return self;
}
#pragma mark 对象初始化-类方法
+(instancetype)initWithFrame : (CGRect) frame
andWithSelectedTextColor : (UIColor*) selectedTextColor
andWithUnselectedTextColor : (UIColor*) unselectedTextColor
andWithSelectedTextBackground : (UIColor*) selectedTextBackground
andWithUnselectedTextBackground : (UIColor*) unselectedTextBackground
andWithTextFont : (UIFont*) textFont
andWithSelectedLineImage : (UIImage*) selectedLineImage
andWithUnselectedLineImage : (UIImage*) unselectedLineImage
andWithLineImageHeight : (CGFloat) lineImageHeight
andWithMax : (NSInteger) max
{
ZJQBOSwipeMenuOption* option = [[ZJQBOSwipeMenuOption alloc] initWithFrame:frame
andWithSelectedTextColor:selectedTextColor
andWithUnselectedTextColor:unselectedTextColor
andWithSelectedTextBackground:selectedTextBackground
andWithUnselectedTextBackground:unselectedTextBackground
andWithTextFont:textFont
andWithSelectedLineImage:selectedLineImage
andWithUnselectedLineImage:unselectedLineImage
andWithLineImageHeight:lineImageHeight
andWithMax:max];
return option;
}
@end
ZJQBOSwipeMenuOption.h
//
// ZJQSwipeMenuView.h
// demo010
//
// Created by zhoujianqiang on 15/9/26.
// Copyright © 2015年 zhoujianqiang. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "ZJQBOSwipeMenuOption.h"
@protocol ZJQSwipeMenuViewDelegate <NSObject>
-(void)menuClickedAtIndex : (NSInteger) index;
@end
@interface ZJQSwipeMenuView : UIView
@property (nonatomic,strong) NSMutableArray* menus; //菜单数组:字符串数组类型,例如[@"菜单1",@"菜单2",...]
@property (nonatomic,strong) ZJQBOSwipeMenuOption* option;//菜单参数
@property (nonatomic,strong) id <ZJQSwipeMenuViewDelegate> delegate;//委托代理
-(instancetype)initWithMenus : (NSMutableArray*) menus
andWithOption : (ZJQBOSwipeMenuOption*) option;
@end
ZJQSwipeMenuView.m
//
// ZJQSwipeMenuView.m
// demo010
//
// Created by zhoujianqiang on 15/9/26.
// Copyright © 2015年 zhoujianqiang. All rights reserved.
//
#import "ZJQSwipeMenuView.h"
#define TAG_MENU 10000 //菜单默认起始tag属性值
#define TAG_LINE 20000 //菜单下划线默认起始tag属性值
@implementation ZJQSwipeMenuView
{
@private
CGFloat menuWidth_;//单个菜单占用的宽度
NSInteger count_;//总的菜单个数
NSInteger showedCount_;//屏幕显示的菜单个数
NSInteger rightIndexInAllMenus_;//最右边菜单索引号,在整个菜单数组中从0开始计数的
BOOL hasUnshowedMenu_;//是否有屏幕未展示的菜单,如果菜单总数超过菜单上限,那么肯定为YES
NSInteger selectedMenuIndex_;//当前选择的菜单索引号
CGPoint touchBeginPoint_;//触摸移动开始位置
CGFloat minX_;//菜单区起点x最小值
CGFloat maxX_;//菜单区起点x最大值
}
#pragma mark --------> 构造器 <--------
-(instancetype)initWithMenus : (NSMutableArray*) menus
andWithOption : (ZJQBOSwipeMenuOption*) option
{
if (self=[super init]) {
_menus=menus;
_option=option;
[self _init];
}
return self;
}
#pragma mark --------> 初始化 <--------
-(void)_init {
[self _initView];
[self _initVariables];
[self _initMenus];
}
-(void)_initView{
self.frame=_option.frame;//菜单区frame
}
-(void)_initVariables{
count_=_menus.count;//总的菜单个数
showedCount_=(count_>_option.max)?_option.max:count_;//屏幕显示的菜单个数,如果超过菜单显示上限,则后面的不显示
CGFloat width = self.frame.size.width;//菜单区的宽度
CGFloat frameX=self.frame.origin.x;
menuWidth_=width/showedCount_;//单个菜单占用的宽度
rightIndexInAllMenus_=showedCount_-1;//最右边菜单索引号
selectedMenuIndex_=0;//屏幕上被选中菜单的索引号
hasUnshowedMenu_=(count_>_option.max)?YES:NO;//是否有屏幕未展示的菜单
//重新计算菜单区的宽度
CGFloat newWidth = count_*menuWidth_;
newWidth = (newWidth>width)? newWidth:width;
CGRect newFrame = self.frame;
newFrame.size.width=newWidth;
self.frame=newFrame;
//计算菜单区起点x坐标的范围
maxX_=frameX;
minX_=maxX_+width-self.frame.size.width;
}
-(void)_initMenus {
for (int i=0; i<count_; i++) {
//
BOOL isSelected = (selectedMenuIndex_==i);
[self _addMenu:isSelected andWithIndexInShowedMenus:i andWithIndexInAllMenus:i andIsAppnedAtTail:YES];
}
}
#pragma mark --------> tag与菜单项的关系操作区 <--------
-(NSInteger) _getMenuTagWithIndexInAllMenus : (NSInteger) indexInAllMenus{
return TAG_MENU+indexInAllMenus;
}
-(NSInteger) _getIndexInAllMenusWithMenuTag : (NSInteger) menuTag{
return menuTag-TAG_MENU;
}
-(NSInteger) _getLineTagWithIndexInAllMenus : (NSInteger) indexInAllMenus{
return TAG_LINE+indexInAllMenus;
}
-(NSInteger) _getIndexInAllMenusWithLineTag : (NSInteger) lineTag{
return lineTag-TAG_LINE;
}
#pragma mark --------> 添加1项菜单 <--------
-(void)_addMenu : (BOOL) isSelected andWithIndexInShowedMenus : (NSInteger) indexInShowedMenus andWithIndexInAllMenus :(NSInteger) indexInAllMenus andIsAppnedAtTail : (BOOL) isAppendAtTail{
//菜单文字
NSString* menuTitle = _menus[indexInAllMenus];
UILabel* lblTabMenu = [[UILabel alloc]init];
lblTabMenu.frame = CGRectMake(indexInShowedMenus*menuWidth_, 0, menuWidth_, self.frame.size.height-_option.lineImageHeight);
lblTabMenu.backgroundColor=(isSelected)?_option.selectedTextBackground:_option.unselectedTextBackground;
lblTabMenu.text=menuTitle;
lblTabMenu.textColor=(isSelected)?_option.selectedTextColor:_option.unselectedTextColor;
lblTabMenu.font=_option.textFont;
lblTabMenu.textAlignment=NSTextAlignmentCenter;
lblTabMenu.tag=[self _getMenuTagWithIndexInAllMenus:indexInAllMenus];
lblTabMenu.userInteractionEnabled=YES;
UITapGestureRecognizer* tapGestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(_menuClicked:)];
[lblTabMenu addGestureRecognizer:tapGestureRecognizer];
UIImageView* ivLine = [[UIImageView alloc]init];
ivLine.image = (isSelected)?_option.selectedLineImage:_option.unselectedLineImage;
ivLine.frame= CGRectMake(indexInShowedMenus*menuWidth_, self.frame.size.height-_option.lineImageHeight, menuWidth_, _option.lineImageHeight);
ivLine.tag=[self _getLineTagWithIndexInAllMenus:indexInAllMenus];
if (isAppendAtTail) {
[self addSubview:lblTabMenu];
[self addSubview:ivLine];
}else{
//注意插入最前面的时候,顺序要和上面的相反
[self insertSubview:ivLine atIndex:0];
[self insertSubview:lblTabMenu atIndex:0];
}
ivLine.alpha=0;
[UIView animateWithDuration:0.5 animations:^{ ivLine.alpha = 1; } completion:^(BOOL finished){ }];
}
#pragma mark --------> 按钮点击和滑动手势事件区 <--------
-(void) _menuClicked : (UITapGestureRecognizer*) sender {
UILabel* lblMenu = (UILabel*)sender.view;
NSInteger tag = lblMenu.tag;
NSInteger menuIndex = [self _getIndexInAllMenusWithMenuTag:tag];
[self _didSelectMenuAtIndex:menuIndex];
//让delegate去继续执行
if (_delegate) {
if ([_delegate respondsToSelector:@selector(menuClickedAtIndex:)]) {
[_delegate menuClickedAtIndex:menuIndex];
}
}
}
-(void) _didSelectMenuAtIndex : (NSInteger) menuIndex {
//将之前选择的菜单取消选择
NSInteger lblOldMenuTag = [self _getMenuTagWithIndexInAllMenus:selectedMenuIndex_];
UILabel* lblOldMenu = (UILabel*) [self viewWithTag:lblOldMenuTag];
lblOldMenu.backgroundColor=_option.unselectedTextBackground;
lblOldMenu.textColor=_option.unselectedTextColor;
NSInteger oldLineTag = [self _getLineTagWithIndexInAllMenus:selectedMenuIndex_];
UIImageView* ivOldLine = (UIImageView*) [self viewWithTag:oldLineTag];
ivOldLine.image=_option.unselectedLineImage;
//选择当前点中的菜单
NSInteger lblMenuTag = [self _getMenuTagWithIndexInAllMenus:menuIndex];
UILabel* lblMenu = (UILabel*) [self viewWithTag:lblMenuTag];
lblMenu.backgroundColor=_option.selectedTextBackground;
lblMenu.textColor=_option.selectedTextColor;
NSInteger lineTag = [self _getLineTagWithIndexInAllMenus:menuIndex];
UIImageView* ivLine = (UIImageView*) [self viewWithTag:lineTag];
ivLine.image=_option.selectedLineImage;
//更新当前选中的菜单索引
selectedMenuIndex_=menuIndex;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch* touch = [touches anyObject];
touchBeginPoint_=[touch locationInView:self];
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch* touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
//x坐标变化
CGFloat xChanged = point.x-touchBeginPoint_.x;
//xChanged<0表示向左移动,xChanged>0表示向右移动
//判断是否可以移动菜单
BOOL isCanMoveMenu = NO;
CGFloat newX = self.frame.origin.x+xChanged;
isCanMoveMenu = (newX>=minX_ && newX<=maxX_);
//修改菜单区frame
CGRect newFrame = self.frame;
if (isCanMoveMenu) {
newFrame.origin.x=newFrame.origin.x+xChanged;
}else{
if (xChanged>0) {
newFrame.origin.x=maxX_;
}else{
newFrame.origin.x=minX_;
}
}
self.frame=newFrame;
}
@end
调用方法:
ViewController996.h
//
// ViewController996.h
// demo010
//
// Created by zhoujianqiang on 15/9/26.
// Copyright © 2015年 zhoujianqiang. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "ZJQBOSwipeMenuOption.h"
#import "ZJQSwipeMenuView.h"
@interface ViewController996 : UIViewController<ZJQSwipeMenuViewDelegate>
@property (nonatomic,strong) ZJQSwipeMenuView* swipeMenuView;
@property (nonatomic,strong) ZJQBOSwipeMenuOption* menuOption;
@end
ViewController996.m
//
// ViewController996.m
// demo010
//
// Created by zhoujianqiang on 15/9/26.
// Copyright © 2015年 zhoujianqiang. All rights reserved.
//
#import "ViewController996.h"
#define IOS7 [[[UIDevice currentDevice]systemVersion] floatValue] >= 7.0 //判断SDK版本号是否是7.0或7。0以上
@interface ViewController996 ()
@end
@implementation ViewController996
#pragma mark ----------> 系统方法区 <----------
- (void)viewDidLoad {
[super viewDidLoad];
[self _init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark ----------> 初始化 <----------
-(void)_init{
if (IOS7) {
self.edgesForExtendedLayout=UIRectEdgeNone;
}
self.title=@"Swipe Menu";
[self _initPropertys];
}
-(void)_initPropertys{
CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, 40);
_menuOption = [ZJQBOSwipeMenuOption initWithFrame:frame andWithSelectedTextColor:[UIColor redColor] andWithUnselectedTextColor:[UIColor blackColor] andWithSelectedTextBackground:[UIColor whiteColor] andWithUnselectedTextBackground:[UIColor whiteColor] andWithTextFont:[UIFont systemFontOfSize:13] andWithSelectedLineImage:[UIImage imageNamed:@"r"] andWithUnselectedLineImage:[UIImage imageNamed:@"w"] andWithLineImageHeight:3 andWithMax:6];
NSMutableArray* menus = [[NSMutableArray alloc]init];
for (int i=0; i<10; i++) {
[menus addObject:[NSString stringWithFormat:@"菜单%d",i]];
}
_swipeMenuView = [[ZJQSwipeMenuView alloc]initWithMenus:menus andWithOption:_menuOption];
[self.view addSubview:_swipeMenuView];
_swipeMenuView.delegate=self;
}
#pragma mark ----------> 实现ZJQSwipeMenuViewDelegate中的方法 <----------
-(void)menuClickedAtIndex:(NSInteger)index{
NSLog(@"menuClickedAtIndex:index=%ld,%@",index,_swipeMenuView.menus[index]);
}
@end
效果图:
完整工程代码为附件中的demo010.zip