VTMagic
有很多开发者曾尝试模仿写出类似网易、腾讯等应用的菜单分页组件,但遍观其设计,大多都比较粗糙,不利于后续维护和扩展。琢磨良久,最终决定开源这个耗时近两年打磨而成的框架,以便大家可以快速实现类似需求,而不用把大量的精力浪费在重复造轮子的过程中,VTMagic目前在多个项目中稳定运行一年多。
特性概要
- 每个页面都是一个完整的控制器,友好支持个性化自定义;
- 页面切换时能准确触发相应的生命周期方法(
viewWillAppear:
等),便于管理各自页面的数据加载和其它逻辑处理; - 导航栏支持多种布局样式,包括自适应文本宽度、自动平分、居中布局以及自定义宽度等;
- 可以在任意子控制器中,通过
self.magicController
获取最近的上层主控制器,方便跨层级处理逻辑; - 支持内嵌webview,若滑动手势无法响应,可以通过
handlePanGesture:
解决; - 支持页面重用和横竖屏切换;
- 更多特性请参见
VTMagicView.h
文件。
使用
VTMagic支持CocoaPods,只需在Podfile文件中添加如下代码即可:
pod "VTMagic"
提示:在使用Pod的过程中可能会遇到无法搜到VTMagic的情况,这是因为VTMagic最近才上传到CocoaPods,你需要更新一下本地的Pod仓库:$ pod repo udpate
,或者你也可以尝试一下升级Pod:$ sudo gem install cocoapods
$ pod setup
。
当然,假如你们的项目暂时还不支持Pod,你可以先下载VTMagic,然后再将文件夹VTMagic
拖到你们的项目里面,最后再import头文件VTMagic.h
即可。
import "VTMagic.h"
集成
关于VTMagic的集成方法主要有以下两种:
1. 直接实例化VTMagicController对象,然后添加到当前控制器中。
- (void)viewDidLoad
{
[super viewDidLoad];
[self addChildViewController:self.magicController];
[self.view addSubview:_magicController.view];
[_magicController.magicView reloadData];
}
- (VTMagicController *)magicController
{
if (!_magicController) {
_magicController = [[VTMagicController alloc] init];
_magicController.magicView.navigationColor = [UIColor whiteColor];
_magicController.magicView.sliderColor = [UIColor redColor];
_magicController.magicView.layoutStyle = VTLayoutStyleDivide;
_magicController.magicView.switchStyle = VTSwitchStyleDefault;
_magicController.magicView.navigationHeight = 40.f;
_magicController.magicView.dataSource = self;
_magicController.magicView.delegate = self;
}
return _magicController;
}
2. 继承VTMagicController,然后在viewDidLoad中完成相应配置。
#import "VTMagicController.h"
@interface ViewController : VTMagicController
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.magicView.navigationColor = [UIColor whiteColor];
self.magicView.sliderColor = [UIColor redColor];
self.magicView.layoutStyle = VTLayoutStyleDefault;
self.magicView.switchStyle = VTSwitchStyleDefault;
self.magicView.navigationHeight = 40.f;
self.magicView.dataSource = self;
self.magicView.delegate = self;
[self.magicView reloadData];
}
VTMagicViewDataSource协议
不管是通过以上哪种方法集成的,都需要实现数据源协议< VTMagicViewDataSource >
,主要有以下三个方法:
- (NSArray<NSString *> *)menuTitlesForMagicView:(VTMagicView *)magicView
{
return _menuList;
}
- (UIButton *)magicView:(VTMagicView *)magicView menuItemAtIndex:(NSUInteger)itemIndex
{
static NSString *itemIdentifier = @"itemIdentifier";
UIButton *menuItem = [magicView dequeueReusableItemWithIdentifier:itemIdentifier];
if (!menuItem) {
menuItem = [UIButton buttonWithType:UIButtonTypeCustom];
[menuItem setTitleColor:RGBCOLOR(50, 50, 50) forState:UIControlStateNormal];
[menuItem setTitleColor:RGBCOLOR(169, 37, 37) forState:UIControlStateSelected];
menuItem.titleLabel.font = [UIFont fontWithName:@"Helvetica" size:16.f];
}
return menuItem;
}
- (UIViewController *)magicView:(VTMagicView *)magicView viewControllerAtPage:(NSUInteger)pageIndex
{
if (0 == pageIndex) {
static NSString *recomId = @"recom.identifier";
VTRecomViewController *recomViewController = [magicView dequeueReusablePageWithIdentifier:recomId];
if (!recomViewController) {
recomViewController = [[VTRecomViewController alloc] init];
}
return recomViewController;
}
static NSString *gridId = @"grid.identifier";
VTGridViewController *gridViewController = [magicView dequeueReusablePageWithIdentifier:gridId];
if (!gridViewController) {
gridViewController = [[VTGridViewController alloc] init];
}
return gridViewController;
}
集成效果
重要协议
除了数据源协议< VTMagicViewDataSource >
外 ,VTMagic中的重要协议还有< VTMagicViewDelegate >
和< VTMagicReuseProtocol >
。
VTMagicViewDelegate协议
主要用于在主控制器中处理页面切换事件。当子页面显示或消失时,会触发viewDidAppeare:
和viewDidDisappeare:
代理方法;当menuItem被点击时,会触发didSelectItemAtIndex:
方法。
- (void)magicView:(VTMagicView *)magicView viewDidAppeare:(__kindof UIViewController *)viewController atPage:(NSUInteger)pageIndex
{
NSLog(@"pageIndex:%ld viewDidAppeare:%@",pageIndex, viewController.view);
}
- (void)magicView:(VTMagicView *)magicView viewDidDisappeare:(__kindof UIViewController *)viewController atPage:(NSUInteger)pageIndex
{
NSLog(@"pageIndex:%ld viewDidDisappeare:%@",pageIndex, viewController.view);
}
- (void)magicView:(VTMagicView *)magicView didSelectItemAtIndex:(NSUInteger)itemIndex
{
NSLog(@"didSelectItemAtIndex:%ld", (long)itemIndex);
}
VTMagicReuseProtocol
用于子控制器被重用时,清除旧数据、修正页面偏移等逻辑处理。
- (void)vtm_prepareForReuse
{
NSLog(@"clear old data if needed:%@", self);
[self.collectionView setContentOffset:CGPointZero];
}
其它
- 你可以在任意子控制器中,通过self.magicController获取最近的上层主控制器,magicController遵循协议
< VTMagicProtocol >
,以便完成一些必要的跨层级的逻辑处理,前提是你需要import<VTMagic/VTMagic.h>
文件。
NSInteger currentPage = self.magicController.currentPage;
UIViewController *viewController = self.magicController.currentViewController;
- 切换到指定页面,页面切换有两种方式:
[self.magicView switchToPage:3 animated:YES];
[self.magicController switchToPage:3 animated:YES];
- 获取指定页面控制器,同样有两种方式:
UIViewController *viewController = [self.magicView viewControllerAtPage:3];
UIViewController *viewController = [self.magicController viewControllerAtPage:3];
结束语
最后,按照惯例,如果你喜欢这个轮子,请留下一颗star,这是对作者最大的鼓励和支持,拜谢!!!假如你有更好的想法或方案,也欢迎提交pull request!!!GitHub地址