iOS之多页面嵌套(WMPageController)

目录
    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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,640评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,254评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,011评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,755评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,774评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,610评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,352评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,257评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,717评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,894评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,021评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,735评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,354评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,936评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,054评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,224评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,974评论 2 355

推荐阅读更多精彩内容

  • 风过后,我就像一张白纸 搁在泥土的方桌上 上面落满了云朵的暗影 还疯长着草木的纠结 我知道,风落在了另一张纸上 那...
    甘肃子溪阅读 103评论 5 4
  • 我们在编写Web应用时,经常需要对页面做一些安全控制,比如:对于没有访问权限的用户需要转到登录表单页面。要实现访问...
    PrimaryKeyEnoch阅读 9,126评论 16 17
  • 晴雯在十二钗又副册之首,晴雯的判词如下: 霁月难逢,彩云易散。心比天高,身为下贱。风流灵巧招人怨,寿夭多因诽谤生。...
    雨林中的阳光阅读 206评论 0 4