github下載地址:https://github.com/SPStore/SPPageMenu
雖然這種工具網上已經多得不能再多了诺核,但是有兩大功能是它們所欠缺的:
1、 跟蹤器在跟蹤按鈕的時候裙士,跟蹤器的寬度能夠時刻跟隨按鈕寬度的改變而改變管毙。注意是時刻跟隨夭咬,不是滑動結束的時候才跟隨
2、菜單上按鈕的展示效果有3種:這主要依賴兩個屬性allowBeyondScreen和equalWidths卓舵,具體怎么設置參考demo
第一種:當按鈕數(shù)較多時掏湾,能夠以scrollView的形式左右滑動融击。
第二種:所有按鈕被限制在屏幕寬度之內,每個按鈕等寬匣屡,等間距捣作。
第三種:所有按鈕被限制在屏幕寬度之內工育,每個按鈕根據文字自適應寬度如绸,間距自適應怔接。
當然,我這個工具的功能仍然不夠岸军,很多菜單欄的右側有一個功能按鈕艰赞,點擊這個功能按鈕可以做其他事情方妖,我這個工具暫時沒加這個功能,我有時間一定會加上去雌澄。
屏幕快照 2017-01-11 上午10.55.01.png
.h文件
#import <UIKit/UIKit.h>
@class SPPageMenu;
@protocol SPPageMenuDelegate <NSObject>
@optional
/**
* pageMenu:菜單對象
* index:當前選中的button下標
*/
- (void)pageMenu:(SPPageMenu *)pageMenu buttonClickedAtIndex:(NSInteger)index;
/**
* pageMenu:菜單對象
* fromIndex:上一個被選中的button下標
* toIndex:當前被選中的button下標
*/
- (void)pageMenu:(SPPageMenu *)pageMenu buttonClickedFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
@end
@interface SPPageMenu : UIView
@property (nonatomic, weak) id<SPPageMenuDelegate> delegate;
/** block方式監(jiān)聽button被點擊镐牺,外界可選擇代理方式睬涧,也可以選擇block方式 */
@property (nonatomic, copy) void(^buttonClickedBlock)(NSInteger index);
@property (nonatomic, copy) void(^buttonClicked_from_to_Block)(NSInteger fromIndex, NSInteger toIndex);
/** button之間的間距,默認為30 */
@property (nonatomic, assign) CGFloat spacing;
/** 第一個button的左邊距宙地,默認為間距的一半 */
@property (nonatomic, assign) CGFloat firstButtonX;
/** button的字體,默認為15號字體 */
@property (nonatomic, strong) UIFont *buttonFont;
/** 選中的button的字體顏色 */
@property (nonatomic, strong) UIColor *selectedTitleColor;
/** 未選中的button字體顏色,默認為黑色 */
@property (nonatomic, strong) UIColor *unSelectedTitleColor;
/** 分割線顏色宅粥,默認為亮灰色 */
@property (nonatomic, strong) UIColor *breaklineColor;
/** 是否顯示分割線,默認為YES */
@property (nonatomic, assign, getter=isShowBreakline) BOOL showBreakline;
/** 是否顯示跟蹤器秽梅,默認為YES */
@property (nonatomic, assign, getter=isShowTracker) BOOL showTracker;
/** 跟蹤器的高度,默認為2.0f */
@property (nonatomic, assign) CGFloat trackerHeight;
/** 跟蹤器的顏色剿牺,默認與選中的button字體顏色一致 */
@property (nonatomic, strong) UIColor *trackerColor;
/** 是否開啟動畫,默認為NO */
@property (nonatomic, assign, getter=isOpenAnimation) BOOL openAnimation;
/** 當以下兩個屬性同時為NO時晒来,spacing和firstButtonX屬性將不受用戶控制湃崩,這是合情合理的 */
/** 是否允許超出屏幕,默認為YES,如果設置了NO,則菜單上的所有button都將示在在屏幕范圍之內攒读,并且默認等寬,整體居中顯示 剪返,如果想要button根據文字自適應寬度脱盲,還要配合下面的“equalWidths”屬性 */
@property (nonatomic, assign, getter=isAllowBeyondScreen) BOOL allowBeyondScreen;
/** 是否等寬宾毒,默認為YES,這個屬性只有在屏幕范圍之內的布局方式才有效 */
@property (nonatomic, assign, getter=isEqualWidths) BOOL equalWidths;
/** 快速創(chuàng)建菜單 */
+ (SPPageMenu *)pageMenuWithFrame:(CGRect)frame array:(NSArray *)array;
/*
* 外界只要告訴該類index,內部會處理哪個button被選中
*/
- (void)selectButtonAtIndex:(NSInteger)index;
/*
* 1.這個方法的功能是實現(xiàn)跟蹤器跟隨scrollView的滾動而滾動;
* 2.調用這個方法必須在scrollViewDidScrollView里面調;
* 3.beginOffset:scrollView剛開始滑動的時候起始偏移量,在scrollViewWillBeginDragging:方法內部獲取起始偏移量;
* 4.scrollView:外面正在拖拽的scrollView;
*/
- (void)moveTrackerFollowScrollView:(UIScrollView *)scrollView beginOffset:(CGFloat)beginOffset;
@end
.m文件
#import "SPPageMenu.h"
@interface SPPageMenu()
@property (nonatomic, strong) UIView *backgroundView;
@property (nonatomic, strong) UIScrollView *scrollView;
/** 該數(shù)組中裝的是字符串 */
@property (nonatomic, strong) NSArray<NSString *> *menuTitleArray;
/** 跟蹤器(跟蹤button的下劃線) */
@property (nonatomic, weak) UIView *tracker;
/** 分割線 */
@property (nonatomic, weak) UIView *breakline;
/** 選中的button */
@property (nonatomic, strong) UIButton *selectedButton;
/** 裝載menuButton的數(shù)組 */
@property (nonatomic, strong) NSMutableArray<UIButton *> *menuButtonArray;
/** 用來判斷外界有沒有設置firstButtonX */
@property (nonatomic, assign, getter=isSettedFirstButtonX) BOOL settedFirstButtonX;
/** 用來判斷外界有沒有設置spacing */
@property (nonatomic, assign, getter=isSettedspacing) BOOL settedspacing;
@end
static NSInteger tagIndex = 2016;
@implementation SPPageMenu
#pragma mark - 初始化方法
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initialize];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
// 初始化設置
- (void)initialize {
_buttonFont = [UIFont systemFontOfSize:15];
_selectedTitleColor = [UIColor redColor];
_unSelectedTitleColor = [UIColor blackColor];
_breaklineColor = [UIColor lightGrayColor];
_showBreakline = YES;
_openAnimation = NO;
_showTracker = YES;
_trackerHeight = 2.0f;
_trackerColor = _selectedTitleColor;
_spacing = 30.0f;
_firstButtonX = 0.5 * _spacing;
_allowBeyondScreen = YES;
_equalWidths = YES;
[self setupSubView];
}
- (void)setupSubView {
// 背景view
UIView *backgroundView = [[UIView alloc] init];
[self addSubview:backgroundView];
self.backgroundView = backgroundView;
// 創(chuàng)建分割線。這個分割線起著很重要的作用幢竹,起初我并沒有創(chuàng)建一個單獨的view作為分割線焕毫,而是利用backgroundView與其子控件scrollView之間的底部設置一定的間隙驶乾,造成分割線的效果级乐。但是這樣會產生一個很嚴重的隱患风科。如果不單獨創(chuàng)建分割線,那么backgroundView的第一個子控件將會是scrollView题山,而正好外界把這個封裝好的菜單添加為控制器view的第一個子控件顶瞳,在默認情況下愕秫,外界控制器的導航欄會將scrollView里面的內容往下壓64豫领。而此菜單欄的高度一般不會設置很高(<64)等恐,這就會導致scrollView里面的子控件看不見。因此囱稽,必須使得backgroundView的第一個子控件不是scrollView战惊。
UIView *breakLine = [[UIView alloc] init];
breakLine.backgroundColor = _breaklineColor;
[self.backgroundView addSubview:breakLine];
self.breakline = breakLine;
// 創(chuàng)建承載菜單button的scrollView
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
[backgroundView addSubview:scrollView];
self.scrollView = scrollView;
scrollView.backgroundColor = [UIColor clearColor];
[self layoutIfNeeded];
}
#pragma mark - public method
// 此方法是留給外界的接口吞获,以創(chuàng)建菜單欄
+ (SPPageMenu *)pageMenuWithFrame:(CGRect)frame array:(NSArray *)array {
SPPageMenu *menu = [[SPPageMenu alloc] initWithFrame:frame];
menu.menuTitleArray = array;
return menu;
}
- (void)setMenuTitleArray:(NSArray<NSString *> *)menuTitleArray {
_menuTitleArray = menuTitleArray;
[self configureMenuButtonToScrollView];
}
#pragma mark - private method
// 添加以及配置menubutton的相關屬性
- (void)configureMenuButtonToScrollView {
// 創(chuàng)建button
CGFloat lastMenuButtonMaxX = 0.0f;
for (int i = 0; i < _menuTitleArray.count; i++) {
UIButton *menuButton = [UIButton buttonWithType:UIButtonTypeCustom];
menuButton.tag = tagIndex + i;
[menuButton addTarget:self action:@selector(menuBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[menuButton setTitle:self.menuTitleArray[i] forState:UIControlStateNormal];
menuButton.backgroundColor = [UIColor clearColor];
menuButton.titleLabel.font = _buttonFont;
menuButton.titleLabel.textAlignment = NSTextAlignmentCenter;
[menuButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[menuButton sizeToFit];
[self.scrollView addSubview:menuButton];
[self.menuButtonArray addObject:menuButton];
// 設置button的frame
[self setupMenuButtonFrame:menuButton
font:_buttonFont
lastMenuButtonMaxX:lastMenuButtonMaxX
index:i];
// 記錄此時menuButton的最大x值
lastMenuButtonMaxX = CGRectGetMaxX(menuButton.frame);
// 設置scrollView的容量
self.scrollView.contentSize = CGSizeMake(lastMenuButtonMaxX + _firstButtonX, 0);
}
// 創(chuàng)建跟蹤器
[self creatTracker:self.scrollView.subviews.firstObject];
[self menuBtnClick:self.scrollView.subviews.firstObject];
}
// 創(chuàng)建跟蹤器
- (void)creatTracker:(UIButton *)button {
UIView *tracker = [[UIView alloc] init];
self.tracker = tracker;
tracker.backgroundColor = _trackerColor;
// 設置tracker的frame
[self setupTrackerFrame:button];
[self.scrollView addSubview:tracker];
}
// button的點擊方法
- (void)menuBtnClick:(UIButton *)button {
// 是不是第一次進入,先默認為YES
static BOOL firstEnter = YES;
// 執(zhí)行代理方法
[self delegatePerformMethodWithFromIndex:self.selectedButton.tag - tagIndex
toIndex:button.tag - tagIndex];
// 回調block
if (self.buttonClickedBlock) {
self.buttonClickedBlock(button.tag - tagIndex);
}
if (self.buttonClicked_from_to_Block) {
self.buttonClicked_from_to_Block(self.selectedButton.tag - tagIndex,button.tag - tagIndex);
}
// 如果點擊的是同一個button,retun掉烤黍,因為后面的操作沒必要重復速蕊。
if (self.selectedButton == button) {
return;
}
if (!firstEnter) {
// 移動跟蹤器
[self moveTracker:button];
}
// 給button添加縮放動畫
if (self.openAnimation) {
[self openAnimationWithLastSelectedButton:self.selectedButton currentSelectedButton:button];
}
// 設置button的字體顏色
[self setupButtonTitleColor:button];
// 記錄當前選中的button
self.selectedButton = button;
// 讓scrollView發(fā)生偏移(重點)
[self moveScrollViewWithSelectedButton:button];
firstEnter = NO;
}
- (void)setupButtonTitleColor:(UIButton *)button {
[self.selectedButton setTitleColor:_unSelectedTitleColor forState:UIControlStateNormal];
[button setTitleColor:_selectedTitleColor forState:UIControlStateNormal];
}
- (void)delegatePerformMethodWithFromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex {
if ([self.delegate respondsToSelector:@selector(pageMenu:buttonClickedAtIndex:)]) {
[self.delegate pageMenu:self buttonClickedAtIndex:toIndex];
}
if ([self.delegate respondsToSelector:@selector(pageMenu:buttonClickedFromIndex:toIndex:)]) {
[self.delegate pageMenu:self buttonClickedFromIndex:fromIndex toIndex:toIndex];
}
}
- (void)moveTracker:(UIButton *)button {
[UIView animateWithDuration:0.25 animations:^{
CGPoint trackerCenter = self.tracker.center;
CGRect trackerFrame = self.tracker.frame;
trackerCenter.x = button.center.x;
trackerFrame.size.width = button.frame.size.width+_spacing;
self.tracker.frame = trackerFrame;
self.tracker.center = trackerCenter;
}];
}
// 點擊button讓scrollView發(fā)生偏移
- (void)moveScrollViewWithSelectedButton:(UIButton *)selectedButton {
// CGRectGetMidX(self.scrollView.frame)指的是屏幕水平中心位置跟啤,它的值是固定不變的
// 選中button的中心x值與scrollView的中心x值之差
CGFloat offSetX = selectedButton.center.x - CGRectGetMidX(self.scrollView.frame);
// scrollView的容量寬與自身寬之差(難點)
CGFloat maxOffsetX = self.scrollView.contentSize.width - self.scrollView.frame.size.width;
// 如果選中的button中心x值小于或者等于scrollView的中心x值腥光,或者scrollView的容量寬度小于scrollView本身武福,此時點擊button時不發(fā)生任何偏移痘番,置offSetX為0
if (offSetX <= 0 || maxOffsetX <= 0) {
offSetX = 0;
}
// 如果offSetX大于maxOffsetX,說明scrollView已經滑到盡頭,此時button也發(fā)生任何偏移了
else if (offSetX > maxOffsetX){
offSetX = maxOffsetX;
}
[self.scrollView setContentOffset:CGPointMake(offSetX, 0) animated:YES];
}
// 設置tracker的frame
- (void)setupTrackerFrame:(UIButton *)button {
CGFloat trackerH = _trackerHeight;
CGFloat trackerW = button.frame.size.width+_spacing;
CGFloat trackerX = button.frame.origin.x-0.5*_spacing;
CGFloat trackerY = self.scrollView.frame.size.height - trackerH;
self.tracker.frame = CGRectMake(trackerX, trackerY, trackerW, trackerH);
}
- (void)setupMenuButtonFrame:(UIButton *)menuButton font:(UIFont *)buttonFont lastMenuButtonMaxX:(CGFloat)lastMenuButtonMaxX index:(NSInteger)index {
// canScroll的狀態(tài)決定著菜單中的button的布局方式
// menuButton的寬度
CGFloat menuButtonW = [menuButton.titleLabel.text boundingRectWithSize:CGSizeMake(MAXFLOAT, 0) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:_buttonFont} context:nil].size.width;
CGFloat menuButtonH = self.scrollView.frame.size.height-1;
CGFloat menuButtonX = (index == 0) ? _firstButtonX : (lastMenuButtonMaxX + _spacing);
CGFloat menuButtonY = 0;
menuButton.frame = CGRectMake(menuButtonX, menuButtonY, menuButtonW, menuButtonH);
}
- (void)resetMenuButtonFrame {
__block CGFloat lastMenuButtonMaxX = 0.0f;
if (_allowBeyondScreen) { // 允許超出屏幕
[self.menuButtonArray enumerateObjectsUsingBlock:^(UIButton * _Nonnull menuButton, NSUInteger idx, BOOL * _Nonnull stop) {
menuButton.titleLabel.font = self.buttonFont;
[self setupMenuButtonFrame:menuButton font:_buttonFont lastMenuButtonMaxX:lastMenuButtonMaxX index:idx];
lastMenuButtonMaxX = CGRectGetMaxX(menuButton.frame);
}];
} else { // 不允許超出屏幕
if (_equalWidths) { // 等寬
[self.menuButtonArray enumerateObjectsUsingBlock:^(UIButton * _Nonnull menuButton, NSUInteger idx, BOOL * _Nonnull stop) {
menuButton.titleLabel.font = self.buttonFont;
CGFloat menuButtonW = (self.scrollView.frame.size.width-2*_firstButtonX-(self.menuTitleArray.count-1)*_spacing) / self.menuTitleArray.count;
CGFloat menuButtonH = self.scrollView.frame.size.height-1;
CGFloat menuButtonX = _firstButtonX + idx * (menuButtonW+_spacing);
CGFloat menuButtonY = 0;
menuButton.backgroundColor = [UIColor clearColor];
menuButton.frame = CGRectMake(menuButtonX, menuButtonY, menuButtonW, menuButtonH);
}];
} else { // 不等寬(根據文字返回寬度,間距自適應)
CGFloat menuButtonW_Sum = 0;
NSMutableArray *menuButtonW_Array = [NSMutableArray array];
CGFloat scrollViewWidth = self.scrollView.frame.size.width;
NSInteger count = self.menuTitleArray.count;
// 提前計算button寬
for (NSString *title in self.menuTitleArray) {
CGFloat menuButtonW = [title boundingRectWithSize:CGSizeMake(MAXFLOAT, 0) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:_buttonFont} context:nil].size.width;
// 求出所有button的寬度之和汞舱,目的是算出間距
menuButtonW_Sum += menuButtonW;
[menuButtonW_Array addObject:@(menuButtonW)];
}
_spacing = (scrollViewWidth - menuButtonW_Sum) / (count+1);
[self.menuButtonArray enumerateObjectsUsingBlock:^(UIButton * _Nonnull menuButton, NSUInteger idx, BOOL * _Nonnull stop) {
CGFloat menuButtonW = [menuButtonW_Array[idx] floatValue];
CGFloat menuButtonH = self.scrollView.frame.size.height-1;
CGFloat menuButtonX = _spacing + lastMenuButtonMaxX;
CGFloat menuButtonY = 0;
menuButton.frame = CGRectMake(menuButtonX, menuButtonY, menuButtonW, menuButtonH);
lastMenuButtonMaxX = CGRectGetMaxX(menuButton.frame);
}];
}
}
// 設置scrollView的容量
self.scrollView.contentSize = CGSizeMake(lastMenuButtonMaxX + _firstButtonX, 0);
}
#pragma mark - 基本布局
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat w = self.frame.size.width;
CGFloat h = self.frame.size.height;
self.backgroundView.frame = CGRectMake(0, 0, w, h);
self.breakline.frame = CGRectMake(0, h - 1, w, 1);
// 減_breaklineHeight是為了有分割線的效果
self.scrollView.frame = CGRectMake(0, 0, w, h);
}
#pragma mark - setter方法
- (NSMutableArray *)menuButtonArray {
if (!_menuButtonArray) {
_menuButtonArray = [NSMutableArray array];
}
return _menuButtonArray;
}
// 設置button的間距
- (void)setspacing:(CGFloat)spacing {
_spacing = spacing;
// 外界是否設置了spacing伍纫,如果能進來,說明設置了. 因此在內部不要調用該set方法
_settedspacing = YES;
// 如果外界沒有設置firstButtonX,默認為新的spacing的一半
if (!_settedFirstButtonX) {
_firstButtonX = 0.5 * spacing;
}
// 重設button的frame
[self resetMenuButtonFrame];
UIButton *menuButton = self.menuButtonArray.firstObject;
[self setupTrackerFrame:menuButton];
}
// 設置第一個button的左間距
- (void)setFirstButtonX:(CGFloat)firstButtonX {
_firstButtonX = firstButtonX;
// 外界是否設置了firstButtonX昂芜,如果能進來莹规,說明設置了. 因此在內部不要調用該set方法
_settedFirstButtonX = YES;
[self resetMenuButtonFrame];
UIButton *menuButton = self.menuButtonArray.firstObject;
[self setupTrackerFrame:menuButton];
}
// 設置字體,字體變了泌神,button的frame和跟蹤器的frame需要重新設置
- (void)setButtonFont:(UIFont *)buttonFont {
_buttonFont = buttonFont;
[self resetMenuButtonFrame];
UIButton *menuButton = self.menuButtonArray.firstObject;
[self setupTrackerFrame:menuButton];
}
// 設置選中的button文字顏色
- (void)setSelectedTitleColor:(UIColor *)selectedTitleColor {
_selectedTitleColor = selectedTitleColor;
[self.selectedButton setTitleColor:selectedTitleColor forState:UIControlStateNormal];
self.tracker.backgroundColor = selectedTitleColor;
}
// 設置沒有選中的button文字顏色
- (void)setUnSelectedTitleColor:(UIColor *)unSelectedTitleColor {
_unSelectedTitleColor = unSelectedTitleColor;
for (UIButton *menuButton in self.menuButtonArray) {
if (menuButton == _selectedButton) {
continue; // 跳過選中的那個button
}
[menuButton setTitleColor:unSelectedTitleColor forState:UIControlStateNormal];
}
}
// 設置分割線顏色
- (void)setBreaklineColor:(UIColor *)breaklineColor {
_breaklineColor = breaklineColor;
self.breakline.backgroundColor = breaklineColor;
}
// 設置是否顯示分割線
- (void)setShowBreakline:(BOOL)showBreakline {
_showBreakline = showBreakline;
self.breakline.hidden = !showBreakline;
}
// 設置是否顯示跟蹤器
- (void)setShowTracker:(BOOL)showTracker {
_showTracker = showTracker;
self.tracker.hidden = !showTracker;
}
// 設置跟蹤器的高度
- (void)setTrackerHeight:(CGFloat)trackerHeight {
_trackerHeight = trackerHeight;
CGRect trackerFrame = self.tracker.frame;
trackerFrame.size.height = trackerHeight;
trackerFrame.origin.y = self.scrollView.frame.size.height - trackerHeight;
self.tracker.frame = trackerFrame;
}
// 設置跟蹤器的顏色
- (void)setTrackerColor:(UIColor *)trackerColor {
_trackerColor = trackerColor;
self.tracker.backgroundColor = trackerColor;
}
// 設置是否開啟動畫
- (void)setOpenAnimation:(BOOL)openAnimation {
_openAnimation = openAnimation;
if (openAnimation) {
// 取出第一個button
UIButton *menuButton = [self.menuButtonArray firstObject];
// 如果外界開啟了動畫舞虱,則給第一個button加上放大動畫。如果不這樣做母市,外界開啟動畫后矾兜,第一個button是不會有放大效果的,只有點擊了其它button之后才會有動畫效果患久。
CABasicAnimation *animation = [self enlargeAnimation];
[menuButton.titleLabel.layer addAnimation:animation forKey:@"animation"];
} else {
// 遍歷所有的button椅寺,如果外界關閉了動畫,則將所有button上動畫移除
[self.menuButtonArray enumerateObjectsUsingBlock:^(UIButton* _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj.titleLabel.layer removeAllAnimations];
}];
}
}
// 返回放大的動畫
- (CABasicAnimation *)enlargeAnimation {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.fromValue = [NSNumber numberWithFloat:1.0f];
animation.toValue = [NSNumber numberWithFloat:1.2f];
animation.duration = 0.1;
animation.repeatCount = 1;
// 以下兩個屬性是讓動畫保持動畫結束的狀態(tài)
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
animation.autoreverses = NO;
return animation;
}
// 返回縮小動畫
- (CABasicAnimation *)narrowAnimation {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.fromValue = [NSNumber numberWithFloat:1.2f];
animation.toValue = [NSNumber numberWithFloat:1.0f];
animation.duration = 0.1;
animation.repeatCount = 1;
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
animation.autoreverses = NO;
return animation;
}
// 開啟動畫
- (void)openAnimationWithLastSelectedButton:(UIButton *)lastSelectedButton currentSelectedButton:(UIButton *)currentSelectedButton {
CABasicAnimation *animation1 = [self enlargeAnimation];
CABasicAnimation *animation2 = [self narrowAnimation];
[lastSelectedButton.titleLabel.layer addAnimation:animation2 forKey:@"animation2"];
[currentSelectedButton.titleLabel.layer addAnimation:animation1 forKey:@"animation1"];
}
// 是否允許超出屏幕
- (void)setAllowBeyondScreen:(BOOL)allowBeyondScreen {
_allowBeyondScreen = allowBeyondScreen;
// 如果不能超出屏幕蒋失,且外界沒有設置spacing返帕,讓間距默認為0.
if (!self.allowBeyondScreen && !_settedspacing) {
_spacing = 0.0f;
_firstButtonX = 0.0f;
}
[self resetMenuButtonFrame];
UIButton *menuButton = self.menuButtonArray.firstObject;
[self setupTrackerFrame:menuButton];
}
// 是否讓button等寬
- (void)setEqualWidths:(BOOL)equalWidths {
_equalWidths = equalWidths;
[self resetMenuButtonFrame];
UIButton *menuButton = self.menuButtonArray.firstObject;
[self setupTrackerFrame:menuButton];
}
#pragma mark - 提供給外界的方法
- (void)selectButtonAtIndex:(NSInteger)index{
UIButton *selectedBtn = (UIButton *)self.menuButtonArray[index];
[self menuBtnClick:selectedBtn];
}
- (void)moveTrackerFollowScrollView:(UIScrollView *)scrollView beginOffset:(CGFloat)beginOffset {
// dragging是scrollView的一個屬性, 如果為YES高镐,說明用戶中正在拖拽scrollView溉旋。
// 如果用戶在外面調用了這個方法 那么本方法會在點擊菜單按鈕的時候和用戶拖拽外面的scrollView的時候調用.
// 如果是用戶點擊菜單按鈕進入的此方法,那dragging必然為NO(沒有拖拽)嫉髓,并且沒有在減速,此時直接retun邑闲,讓跟蹤器跟著菜單按鈕走算行。
// 如果是用戶在外面拖拽scrollView而進入的此方法,那dragging必然為YES(正在拖拽)苫耸,此時讓跟蹤器跟著scrollView的偏移量走
// 當手指松開州邢,decelerating屬性為YES,表示scrolview正在減速
if (!scrollView.dragging && !scrollView.decelerating) {
return;
}
if (scrollView.contentOffset.x < 0 || scrollView.contentOffset.x > scrollView.contentSize.width-scrollView.bounds.size.width) {
return;
}
CGFloat offSetX = scrollView.contentOffset.x;
CGFloat tempProgress = offSetX / scrollView.bounds.size.width;
CGFloat progress = tempProgress - floor(tempProgress);
NSInteger oldIndex;
NSInteger currentIndex;
if (offSetX - beginOffset >= 0) { // 向左滑動
oldIndex = offSetX / scrollView.bounds.size.width;
currentIndex = oldIndex + 1;
if (currentIndex >= self.menuTitleArray.count) {
currentIndex = oldIndex - 1;
}
if (offSetX - beginOffset == scrollView.bounds.size.width) {// 滾動停止了
progress = 1.0;
currentIndex = oldIndex;
}
} else { // 向右滑動
currentIndex = offSetX / scrollView.bounds.size.width;
oldIndex = currentIndex + 1;
progress = 1.0 - progress;
}
[self moveTrackerWithProgress:progress fromIndex:oldIndex toIndex:currentIndex];
}
- (void)moveTrackerWithProgress:(CGFloat)progress fromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex {
UIButton *oldButton = self.menuButtonArray[fromIndex];
UIButton *currentButton = self.menuButtonArray[toIndex];
CGFloat xDistance = currentButton.frame.origin.x - oldButton.frame.origin.x;
CGFloat wDistance = currentButton.frame.size.width - oldButton.frame.size.width;
CGRect newFrame = self.tracker.frame;
newFrame.origin.x = oldButton.frame.origin.x + xDistance * progress - 0.5*_spacing;
newFrame.size.width = oldButton.frame.size.width + wDistance * progress + _spacing;
self.tracker.frame = newFrame;
}
@end
github下載地址:https://github.com/SPStore/SPPageMenu