iOS平台默认的tab位于屏幕下方,碰到了实现位于屏幕上方tab的需求,在Github上找到了一个满足需要的项目,移植到了工程中。先上个效果图:
具体使用方法这里就不具体说了,有需要可以移步到开源项目页查看。源码代码比较简单,实现两个UICollectionView即可完成基本的功能效果。
控件框架
控件继承自UIViewController,初始化接口需要传入标签的高度,开发者需要调用reloadData:andSubViewdisplayClasses:withParams:接口刷新标签与标签页面。
标签title通过第一个数组参数传入。
标签页由第二个数组参数传入,具体内容为标签页对应的class,控件内部会自动创建标签页。
如果需要给标签页传递参数,可以通过第三个参数。不过可惜的是实现使用了硬编码,限制了传参的灵活性。参见以下代码:
if (self.params.count != 0) {
if (![cachedViewController valueForKeyPath:@"XBParam"]) {
[cachedViewController setValue:self.params[indexPath.item] forKeyPath:@"XBParam"];
}
}
两个UICollectionView
标签与标签页组成了该控件的主体内容。它们在控件初始化时补创建,在控件的viewDidLoad接口中被加入到子view中,并在开发者调用上面的reloadData接口中被刷新显示。这里给出UICollectionView的创建代码:
- (void)setupCollectionView
{
//初始化标签布局
UICollectionViewFlowLayout *tagFlowLayout = [[UICollectionViewFlowLayout alloc]init];
tagFlowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
tagFlowLayout.minimumLineSpacing = 0;
tagFlowLayout.minimumInteritemSpacing = 0;
self.tagFlowLayout = tagFlowLayout;
//初始化标签View
UICollectionView *tagCollectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:tagFlowLayout];
[tagCollectionView registerClass:[XBTagTitleCell class] forCellWithReuseIdentifier:kTagCollectionViewCellIdentifier];
tagCollectionView.backgroundColor = [UIColor whiteColor];
tagCollectionView.showsHorizontalScrollIndicator = NO;
tagCollectionView.dataSource = self;
tagCollectionView.delegate = self;
self.tagCollectionView = tagCollectionView;
//初始化页面布局
UICollectionViewFlowLayout *pageFlowLayout = [[UICollectionViewFlowLayout alloc]init];
pageFlowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
pageFlowLayout.minimumLineSpacing = 0;
pageFlowLayout.minimumInteritemSpacing = 0;
self.pageFlowLayout = pageFlowLayout;
//初始化页面View
UICollectionView *pageCollectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:pageFlowLayout];
[pageCollectionView registerClass:[XBPageCell class] forCellWithReuseIdentifier:kPageCollectionViewCellIdentifier];
pageCollectionView.backgroundColor = [UIColor whiteColor];
pageCollectionView.showsHorizontalScrollIndicator = NO;
pageCollectionView.dataSource = self;
pageCollectionView.delegate = self;
pageCollectionView.pagingEnabled = YES;
self.pageCollectionView = pageCollectionView;
}
缓存机制
控件是由一系列的标签业组成,如果显示过的标签页都一直保存在内存中,是对系统的内存使用的巨大浪费。因此控件设计了这样的一个缓存机制:显示过的页面都会加入到缓存中去,但如果页面在超过规定时间没有再次显示的话,控件会将该页面从缓存中删除,进而整个页面也就得到了释放。
- (void)updateViewControllersCaches
{
NSDate *currentDate = [NSDate date];
__weak typeof(self) weakSelf = self;
NSMutableDictionary *tempDic = self.viewControllersCaches;
[self.viewControllersCaches enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSDictionary *obj, BOOL *stop) {
UIViewController *vc = [obj objectForKey:kCachedVCName];
NSDate *cachedTime = [obj objectForKey:kCachedTime];
NSInteger keyInteger = [key integerValue];
NSInteger selectionInteger = weakSelf.selectedIndex;
if (keyInteger != selectionInteger) { //当前不是当前正在展示的cell
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:cachedTime];
if (timeInterval >= weakSelf.graceTime) {
//宽限期到了销毁控制器
[tempDic removeObjectForKey:key];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
}
}
}];
self.viewControllersCaches = tempDic;
}
缺点
- 初始化接口设计缺陷,需要传入标签高度,这个参数本身就是一个配置项,完全可以设定一默认值,开发者可以自行配置。
- 标签页传参不灵活,硬编码实现,参数名固定,且要求所有的标签页都要配置。
- 标签页不支持xib,标签页的创建是通过alloc/init方式自动创建的,可以在些基础上增加多种创建方式。