目录
1. 示例
2. 详细说明
Podfile中导入
pod 'WMPageController'
实现效果如下:
预期效果
1. 示例
ZYTYDataMainViewController : WMPageController
/**
菜单项 数组
*/
@property (nonatomic,copy) NSArray *itemArr;
-(void)setupWM{
// 缓存机制
[self setCachePolicy:WMPageControllerCachePolicyBalanced];
// 这里给titles设置值,否则不出现下滑线
self.titles=self.itemArr;
// 下划线
self.progressWidth = 27;
self.progressColor=[UIColor whiteColor];
self.progressViewBottomSpace = 7;
self.progressHeight=3;
self.progressViewIsNaughty = YES;
// 菜单栏
self.menuViewStyle = WMMenuViewStyleLine;
self.titleFontName = @".PingFang-SC-Regular";
self.titleFontNameSelected = @".PingFang-SC-Bold";
self.titleColorNormal = [UIColor whiteColor];
self.titleColorSelected = [UIColor whiteColor];
self.titleSizeNormal = 15;
self.titleSizeSelected = 17;
[self reloadData]; // 必须+(刷新界面)
}
#pragma mark 覆写dele方法
/**
菜单项 个数
*/
- (NSInteger)numbersOfChildControllersInPageController:(WMPageController *)pageController {
return self.itemArr.count;
}
/**
菜单项 标题
*/
- (NSString *)pageController:(WMPageController *)pageController titleAtIndex:(NSInteger)index {
ZYDataMenuItemModel *itemM=self.itemArr[index];
return itemM.itemName;
}
/**
菜单项 内容控制器
*/
- (UIViewController *)pageController:(WMPageController *)pageController viewControllerAtIndex:(NSInteger)index {
ZYDataMenuItemModel *itemM=self.itemArr[index];
ZYTYDataSecViewController *secVC=[ZYTYDataSecViewController new];
[secVC setPageType:itemM.matchType];
return secVC;
}
/**
菜单项 宽度
*/
- (CGFloat)menuView:(WMMenuView *)menu widthForItemAtIndex:(NSInteger)index {
CGFloat width = [super menuView:menu widthForItemAtIndex:index];
return width-13;
}
/**
菜单视图 frame
*/
- (CGRect)pageController:(WMPageController *)pageController preferredFrameForMenuView:(WMMenuView *)menuView {
return CGRectMake(8, kStatusBarHeight, kScreenWidth-45, 44);
}
/**
内容控制器视图 frame
*/
- (CGRect)pageController:(WMPageController *)pageController preferredFrameForContentView:(WMScrollView *)contentView {
CGFloat originY = CGRectGetMaxY([self pageController:pageController preferredFrameForMenuView:self.menuView]);
return CGRectMake(0, originY, kScreenWidth, kScreenHeight - originY -kTabBarHeight);
}
/**
点击菜单项后会调用本方法
*/
- (void)menuView:(WMMenuView *)menu didSelectedIndex:(NSInteger)index currentIndex:(NSInteger)currentIndex{
[super menuView:menu didSelectedIndex:index currentIndex:currentIndex];
}
#pragma mark 懒加载
/**
菜单项 数组
*/
-(NSArray *)itemArr{
if(!_itemArr){
NSArray *itemArr=@[@[@"英超",@(0)],@[@"欧冠",@(0)],@[@"西甲",@(0)],@[@"德甲",@(0)],@[@"亚洲杯",@(1)],@[@"中超",@(0)],@[@"欧联",@(0)]];
NSMutableArray *tmpMuArr=[NSMutableArray arrayWithCapacity:10];
for(int i=0;i<itemArr.count;i++){
ZYDataMenuItemModel *item=[ZYDataMenuItemModel new];
[item setItemName:itemArr[i][0]];
[item setMatchType:[itemArr[i][1] intValue]];
[tmpMuArr addObject:item];
}
_itemArr=[tmpMuArr copy];
}
return _itemArr;
}
2. 详细说明
WMPageController
@interface WMPageController : UIViewController <WMMenuViewDelegate, WMMenuViewDataSource, UIScrollViewDelegate, WMPageControllerDataSource, WMPageControllerDelegate>
缓存
/**
缓存的机制
WMPageControllerCachePolicyDisabled = -1, // 禁用缓存
WMPageControllerCachePolicyNoLimit = 0, // 默认为无限制 (如果收到内存警告, 会自动切换)
WMPageControllerCachePolicyLowMemory = 1, // 低缓存
WMPageControllerCachePolicyBalanced = 3, // 平衡高低缓存这2种方式 (建议设置)
WMPageControllerCachePolicyHigh = 5 // 高缓存
*/
@property (nonatomic, assign) WMPageControllerCachePolicy cachePolicy;
/**
预加载机制
在停止滑动的时候预加载 n 页
WMPageControllerPreloadPolicyNever = 0, // 从不预加载
WMPageControllerPreloadPolicyNeighbour = 1, // 预加载下一页.
WMPageControllerPreloadPolicyNear = 2 // 预加载相邻页.
*/
@property (nonatomic, assign) WMPageControllerPreloadPolicy preloadPolicy;
dele
/**
dele、dataSource
*/
@property (nonatomic, weak) id<WMPageControllerDelegate> delegate;
@property (nonatomic, weak) id<WMPageControllerDataSource> dataSource;
菜单项视图
/**
菜单项标题数组
*/
@property (nonatomic, nullable, copy) NSArray<NSString *> *titles;
/**
菜单项视图
*/
@property (nonatomic, nullable, weak) WMMenuView *menuView;
//--------------------------- MenuView style、布局 -----------------------
/**
menuView Style
WMMenuViewStyleDefault, // 默认
WMMenuViewStyleLine, // 带下划线 (若要选中字体大小不变,设置选中和非选中大小一样即可)
WMMenuViewStyleTriangle, // 三角形 (progressHeight 为三角形的高, progressWidths 为底边长)
WMMenuViewStyleFlood, // 涌入效果 (填充)
WMMenuViewStyleFloodHollow, // 涌入效果 (空心的)
WMMenuViewStyleSegmented, // 涌入带边框,即网易新闻选项卡
*/
@property (nonatomic, assign) WMMenuViewStyle menuViewStyle;
/**
menuView 布局
WMMenuViewLayoutModeScatter, // 默认的布局模式, item 会均匀分布在屏幕上,呈分散状
WMMenuViewLayoutModeLeft, // Item 紧靠屏幕左侧
WMMenuViewLayoutModeRight, // Item 紧靠屏幕右侧
WMMenuViewLayoutModeCenter, // Item 紧挨且居中分布
*/
@property (nonatomic, assign) WMMenuViewLayoutMode menuViewLayoutMode;
/**
MenuView 总视图左右的间距
*/
@property (nonatomic, assign) CGFloat menuViewContentMargin;
/**
MenuView是否作为 NavigationBar 的 titleView 展示
默认 NO
*/
@property (assign, nonatomic) BOOL showOnNavigationBar;
/**
标题相同间隙
*/
@property (nonatomic, assign) CGFloat itemMargin;
/**
标题间隙
包括头尾两端,所以确保它的数量等于控制器数量 + 1, 默认间隙为 0
*/
@property (nonatomic, nullable, copy) NSArray<NSNumber *> *itemsMargins;
//------------------------------- MenuView标题 ------------------------------
/**
未选中 标题字体大小
*/
@property (nonatomic, assign) CGFloat titleSizeNormal;
/**
选中 标题字体大小
*/
@property (nonatomic, assign) CGFloat titleSizeSelected;
/**
未选中 标题字体名
*/
@property (nonatomic, nullable, copy) NSString *titleFontName;
/**
选中 标题字体名
*/
@property (nonatomic, nullable, copy) NSString *titleFontNameSelected;
/**
未选中 标题颜色
*/
@property (nonatomic, strong) UIColor *titleColorNormal;
/**
选中 标题颜色
*/
@property (nonatomic, strong) UIColor *titleColorSelected;
/**
标题宽度
*/
@property (nonatomic, assign) CGFloat menuItemWidth;
/**
标题宽度数组
*/
@property (nonatomic, nullable, copy) NSArray<NSNumber *> *itemsWidths;
/**
是否自动通过字符串计算标题宽度,
默认为 NO
*/
@property (nonatomic, assign) BOOL automaticallyCalculatesItemWidths;
//------------------------------- 下划线 ---------------------------------
/**
progressView的颜色
默认和选中颜色一致(如果 style 为 Default,则该属性无用)
*/
@property (nonatomic, nullable, strong) UIColor *progressColor;
/**
progressView的宽度(相同宽度)
*/
@property (nonatomic, assign) CGFloat progressWidth;
/**
progressView的宽度数组(不同宽度)
*/
@property (nonatomic, nullable, strong) NSArray *progressViewWidths;
/**
progressView的高度
*/
@property (nonatomic, assign) CGFloat progressHeight;
/**
progressView 到 menuView 底部的距离
*/
@property (nonatomic, assign) CGFloat progressViewBottomSpace;
/**
progressView的圆角
*/
@property (nonatomic, assign) CGFloat progressViewCornerRadius;
/**
下划线是否调皮效果
用于实现腾讯视频新效果,请设置一个较小的 progressWidth
*/
@property (nonatomic, assign) BOOL progressViewIsNaughty;
内容视图
/**
子控制数组
*/
@property (nonatomic, nullable, copy) NSArray<Class> *viewControllerClasses;
/**
scrollView内容视图
*/
@property (nonatomic, nullable, weak) WMScrollView *scrollView;
/**
子控制是否可滚动
*/
@property (nonatomic, assign) BOOL scrollEnable;
/**
子控制器是否动画滚动
*/
@property (nonatomic, assign) BOOL pageAnimatable;
/**
内容视图bounces弹性
*/
@property (nonatomic, assign) BOOL bounces;
/**
当前选中下标
*/
@property (nonatomic, assign) int selectIndex;
/**
当前ViewController(只读)
*/
@property (nonatomic, strong, readonly) UIViewController *currentViewController;
其他属性
/**
values keys 属性可以用于初始化控制器的时候为控制器传值(利用 KVC 来设置)
使用时请确保 key 与控制器的属性名字一致!!(例如:控制器有需要设置的属性 type,那么 keys 所放的就是字符串 @"type")
*/
@property (nonatomic, nullable, strong) NSMutableArray<id> *values;
@property (nonatomic, nullable, strong) NSMutableArray<NSString *> *keys;
/**
用代码设置 contentView 的 contentOffset 之前,请设置 startDragging = YES
*/
@property (nonatomic, assign) BOOL startDragging;
方法
/**
构造方法
@param classes 子控制器数组
@param titles 标题数组
@return 实例
*/
- (instancetype)initWithViewControllerClasses:(NSArray<Class> *)classes andTheirTitles:(NSArray<NSString *> *)titles;
/**
强制重新布局
会调用`-pageController:preferredFrameForContentView:` and `-pageContoller:preferredFrameForMenuView:`
*/
- (void)forceLayoutSubviews;
/**
设置了属性,需要更新界面时调用
*/
- (void)reloadData;
/**
更新指定index的标题内容
@param title 新标题
@param index index下标
*/
- (void)updateTitle:(NSString *)title atIndex:(NSInteger)index;
/**
更新指定index的标题内容、宽
@param title 新标题
@param width 宽
@param index index下标
*/
- (void)updateTitle:(NSString *)title andWidth:(CGFloat)width atIndex:(NSInteger)index;
/**
更新指定index的复杂标题
@param title 新标题
@param index index下标
*/
- (void)updateAttributeTitle:(NSAttributedString *)title atIndex:(NSInteger)index;
/**
是否发送在创建控制器或者视图完全展现在用户眼前时通知观察者,默认为不开启,如需利用通知请开启
*/
@property (nonatomic, assign) BOOL postNotification;
/**
即将进入后台时调用(覆写)
@param notification 通知
*/
- (void)willResignActive:(NSNotification *)notification;
/**
即将回到前台时调用(覆写)
@param notification 通知
*/
- (void)willEnterForeground:(NSNotification *)notification;
@end
WMPageControllerDataSource 协议
@protocol WMPageControllerDataSource <NSObject>
@optional
/**
子控制器的数量
@param pageController pageController
@return 子控制器的数量
*/
- (NSInteger)numbersOfChildControllersInPageController:(WMPageController *)pageController;
/**
index对应的子控制
@param pageController pageController
@param index index
@return index对应的子控制
*/
- (__kindof UIViewController *)pageController:(WMPageController *)pageController viewControllerAtIndex:(NSInteger)index;
/**
index对应的标题
@param pageController pageController
@param index index
@return index对应的标题
*/
- (NSString *)pageController:(WMPageController *)pageController titleAtIndex:(NSInteger)index;
@required
/**
内容视图的frame
@param pageController pageController
@param contentView contentView
@return 内容视图的frame
*/
- (CGRect)pageController:(WMPageController *)pageController preferredFrameForContentView:(WMScrollView *)contentView;
/**
菜单项视图的frame
@param pageController pageController
@param menuView menuView
@return 菜单项视图的frame
*/
- (CGRect)pageController:(WMPageController *)pageController preferredFrameForMenuView:(WMMenuView *)menuView;
@end
WMPageControllerDelegate 协议
@protocol WMPageControllerDelegate <NSObject>
@optional
/**
懒加载,只有在初始化控制器并停止滚动时才会调用此方法。
这意味着如果控制器被缓存并且没有释放,则不会调用此方法
@param pageController pageController
@param viewController viewController
@param info 包含index、title
*/
- (void)pageController:(WMPageController *)pageController lazyLoadViewController:(__kindof UIViewController *)viewController withInfo:(NSDictionary *)info;
/**
viewController被缓存时调用
@param pageController pageController
@param viewController viewController
@param info 包含index、title
*/
- (void)pageController:(WMPageController *)pageController willCachedViewController:(__kindof UIViewController *)viewController withInfo:(NSDictionary *)info;
/**
viewController即将显示时调用
@param pageController pageController
@param viewController 即将显示的viewController
@param info 包含index、title
*/
- (void)pageController:(WMPageController *)pageController willEnterViewController:(__kindof UIViewController *)viewController withInfo:(NSDictionary *)info;
/**
内容视图完全停止滚动时调用(viewController完全显示在用户面前)
@param pageController pageController
@param viewController 即将显示的viewController
@param info 包含index、title
*/
- (void)pageController:(WMPageController *)pageController didEnterViewController:(__kindof UIViewController *)viewController withInfo:(NSDictionary *)info;
@end
WMMenuViewDataSource 协议
@protocol WMMenuViewDataSource <NSObject>
@required
/**
菜单项个数
@param menu WMMenuView
@return 菜单项个数
*/
- (NSInteger)numbersOfTitlesInMenuView:(WMMenuView *)menu;
/**
index对应的菜单项标题
@param menu WMMenuView
@param index index
@return index对应的菜单项标题
*/
- (NSString *)menuView:(WMMenuView *)menu titleAtIndex:(NSInteger)index;
@optional
/**
index对应的角标视图(设置好frame)
@param menu WMMenuView
@param index index
@return index对应的角标视图(设置好frame)
*/
- (UIView *)menuView:(WMMenuView *)menu badgeViewAtIndex:(NSInteger)index;
/**
定制菜单项
此时的 WMMenuView、item 的 frame 是不确定的,所以请勿根据此时的 frame 做计算!
@param menu WMMenuView
@param initialMenuItem 原始菜单项(做修改,或返回自定义子类)
@param index index
@return 定制菜单项
*/
- (WMMenuItem *)menuView:(WMMenuView *)menu initialMenuItem:(WMMenuItem *)initialMenuItem atIndex:(NSInteger)index;
@end
WMMenuViewDelegate 协议
@protocol WMMenuViewDelegate <NSObject>
@optional
/**
是否允许选中
@param menu WMMenuView
@param index 将要选中的index
@return 是否允许选中
*/
- (BOOL)menuView:(WMMenuView *)menu shouldSelesctedIndex:(NSInteger)index;
/**
选中后调用
@param menu WMMenuView
@param index 将要选中的index
@param currentIndex 当前index
*/
- (void)menuView:(WMMenuView *)menu didSelesctedIndex:(NSInteger)index currentIndex:(NSInteger)currentIndex;
/**
index对应的菜单项宽
@param menu WMMenuView
@param index index
@return index对应的菜单项宽
*/
- (CGFloat)menuView:(WMMenuView *)menu widthForItemAtIndex:(NSInteger)index;
/**
index对应的菜单项Margin
@param menu WMMenuView
@param index index
@return index对应的菜单项Margin
*/
- (CGFloat)menuView:(WMMenuView *)menu itemMarginAtIndex:(NSInteger)index;
/**
index对应不同状态的菜单项宽
@param menu WMMenuView
@param state WMMenuItemState
@param index index
@return index对应不同状态的菜单项宽
*/
- (CGFloat)menuView:(WMMenuView *)menu titleSizeForState:(WMMenuItemState)state atIndex:(NSInteger)index;
/**
index对应不同状态的菜单项颜色
@param menu WMMenuView
@param state WMMenuItemState
@param index index
@return index对应不同状态的菜单项颜色
*/
- (UIColor *)menuView:(WMMenuView *)menu titleColorForState:(WMMenuItemState)state atIndex:(NSInteger)index;
/**
重新布局后调用
@param menu WMMenuView
@param menuItem 菜单项
@param index index
*/
- (void)menuView:(WMMenuView *)menu didLayoutItemFrame:(WMMenuItem *)menuItem atIndex:(NSInteger)index;
@end