很久不写了,除了懒之外也肯定不能说项目很紧工作很忙.
今天更新一个很久之前写过的分页加载控制器,为什么要更新这个分页加载这么常见的多如牛毛的轮子...主要是现在几个主流 APP 都有关于这个分页滑动效果的实现,我见过的有:京东,微博,还有爱奇艺,其他的暂时没发现哈.
基本效果:
更新后的主要滑动效果如下:
传送门: Github
(Github上的 readme 并没有更新,看这里就行.)
对于实现以及更多的样式感兴趣的话可以继续往下看.
主要实现:
以上是一些基本效果的实现.大体就是分页条的下划线随着滑动手势的执行所实现的一个稍微有点酷的动画效果.其实实现起来也不麻烦.只要注意切分滑动状态,就可以根据不同状态下的滑动现象很容易分析出实现思路.
最主要的过程就是,将滑动的过程切分为:左滑和右滑 两个部分,再分别将左滑和右滑两个部分切分为:前半部分下划线长度↑(增加)和后半部分下划线长度↓(减少). 总共四中状态,分别针对四中状态监听
- scrollViewDidScroll:
做不同的长度处理,同时在这个过程中,动态的去修改下划线的 center.x 位置就能够实现这个效果.
上一下实现这个过程的核心代码:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGFloat changedW = _pageCellW*2*fabs(x-ScreenW*index) / ScreenW;
_line.frame = CGRectMake(0, _pageBarHeight-_lineHeight, _lineWidth+changedW, _lineHeight);
CGFloat centerX;
if (toLeft) {
if ((x-ScreenW*index) > 0) { //未过半屏: 过半屏之后因为index = (x + ScreenW*0.5) / ScreenW; 所以 index 值会+1
centerX = index * _pageCellW + _pageCellW/2 + changedW/2;
}else{ //划过半屏
centerX = index * _pageCellW + _pageCellW/2 - changedW/2;
}
}else{
if ((x-ScreenW*index) < 0) { //未过半屏
centerX = index * _pageCellW + _pageCellW/2 - changedW/2;
}else{ //划过半屏
centerX = index * _pageCellW + _pageCellW/2 + changedW/2;
}
}
_line.center = CGPointMake(centerX, _pageBarHeight-_lineHeight/2);
}
}
扩展了非常多的实用性的功能,调用方式有以下几种都可以实现:
/**
创建分页控制器 : 自动创建全部控制器(方式一)
@param titlesArray 标题数组
@param controllers 控制器数组
@param onNavigationBar 分页栏是否放在控制器导航栏上
@return 栈顶控制管理器
*/
- (instancetype)initWithTitles:(NSArray *)titlesArray controllers:(NSArray *)controllers onNavigationBar:(BOOL)onNavigationBar;
/**
* 创建分页控制器 : 滑动到相应 index 位置时才去创建相应控制器,此方式不太好传参(方式二)
*
* @param titlesArray 标题数组
* @param controllersClass 要创建的控制器类名数组
* @param onNavigationBar 分页栏是否放在控制器导航栏上
* @return 栈顶控制管理器
*/
- (instancetype)initWithTitles:(NSArray *)titlesArray controllersClass:(NSArray *)controllersClass onNavigationBar:(BOOL)onNavigationBar;
使用:
可以用方式1初始化,传进去实例化好的控制器对象集合,也可以用方式2初始化,传进去未实例化的控制器类集合,等滑动到相应位置时再去动态实例化,可以自由选择实例化方式,选择是否将分页条加载于导航条上,并且已经做了关于 iPhone X 的适配.
同时,实际调用的时候,可以直接push-->XXPageMenuController, 或者将PageMenu添加到 parentViewController/view, 套一层parentViewController以实现导航条上更全面的设置,如果项目有需求的话.
if (indexPath.section == 0) {
XXPageMenuController *pageMenuController = nil;
switch (indexPath.row) {
case 0:
{
NSMutableArray *controllersClass = [NSMutableArray array];
[titles enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[controllersClass addObject:[PageCell2Controller class]];
}];
pageMenuController = [[XXPageMenuController alloc] initWithTitles:titles controllersClass:controllersClass onNavigationBar:YES];
}
break;
case 1:
{
NSMutableArray *controllers = [NSMutableArray array];
[titles enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[controllers addObject:[PageCell1Controller new]];
}];
pageMenuController = [[XXPageMenuController alloc] initWithTitles:titles controllers:controllers onNavigationBar:NO];
pageMenuController.titleColor = [UIColor whiteColor];
pageMenuController.pageBarBgColor = [UIColor grayColor];
pageMenuController.pageBarHeight = 44;
pageMenuController.lineColor = [UIColor orangeColor];
}
break;
case 2:
{
pageMenuController = [[XXPageMenuController alloc] initWithTitles:titles2 controllersClass:@[[PageCell2Controller class],[PageCell2Controller class],[PageCell2Controller class],[PageCell2Controller class]] onNavigationBar:YES];
}
break;
default:
{
pageMenuController = [[XXPageMenuController alloc] initWithTitles:titles2 controllersClass:@[[PageCell1Controller class],[PageCell1Controller class],[PageCell1Controller class],[PageCell2Controller class]] onNavigationBar:NO];
}
break;
}
[self.navigationController pushViewController:pageMenuController animated:YES];
}else{
switch (indexPath.row) {
case 0:
[self.navigationController pushViewController:[Parent1Controller new] animated:YES];
break;
case 1:
[self.navigationController pushViewController:[Parent2Controller new] animated:YES];
break;
case 2:
[self.navigationController pushViewController:[Parent3Controller new] animated:YES];
break;
default:
[self.navigationController pushViewController:[Parent4Controller new] animated:YES];
break;
}
}
基本效果实现以后,除了原有的一些可设置的属性:
/** 分页条高度 */
@property(nonatomic, assign) CGFloat pageBarHeight;
/** 分页条背景色 */
@property (nonatomic,strong) UIColor *pageBarBgColor;
/** 下滑线颜色 */
@property (nonatomic,strong) UIColor *lineColor;
/** 下滑线高度 */
@property (nonatomic,assign) CGFloat lineHeight;
/** 标题颜色 */
@property (nonatomic,strong) UIColor *titleColor;
/** 标题字体 */
@property (nonatomic,strong) UIFont *titleFont;
之外,还对这个小工具做了一些新的,在项目中可能会用到的优化:
/** 标题选中颜色(可不设置) */
@property (nonatomic,strong) UIColor *titleSelectedColor;
/** 下划线长度取值类型 */
@property (nonatomic,assign) LineWidthType lineWidthType;
/** 下划线在条目切换时的动态表现类型 */
@property (nonatomic,assign) LineScrollType lineScrollType;
/**
下划线长度取值类型
- LineWidthTypeStaticShort: 静态短长度,取个固定短值
- LineWidthTypeStaticLong: 静态长度,根据总长度/数量
- LineWidthTypeDynamic: 动态长度,根据文字长度
*/
typedef NS_ENUM(NSInteger, LineWidthType) {
LineWidthTypeStaticShort = 0,
LineWidthTypeStaticLong,
LineWidthTypeDynamic,
};
/**
下划线在条目切换时的动态表现类型
- LineScrollTypeDynamicAnimation: 即时的下划线动态动画
- LineScrollTypeFinishedAnimation: 完成后的下划线动态动画
- LineScrollTypeFinishedLinear: 完成后的下划线线性动画
- LineScrollTypeDynamicLinear: 即时的下划线线性动画(先不做了,实用性完全被LineScrollTypeDynamicAnimation替代了...)
*/
typedef NS_ENUM(NSInteger, LineScrollType) {
LineScrollTypeDynamicAnimation = 0,
LineScrollTypeFinishedAnimation,
LineScrollTypeFinishedLinear,
};
增加了默认选中位置的设置:
/** 默认选择的 index 位置 ,默认值为0*/
- (void)moveToDefaultIndex:(NSInteger)index;
同时也保留了原有的常用的下划线滑动方式:
增加了在滑动即将结束时- scrollViewDidEndDecelerating:
处理的新动画效果(这里用了随机数0/1去 push 的这一条):
实际的使用方式 demo 里都写的很详细,这里是最后留下的传送门,如果您有兴趣使用这个分页条,欢迎使用并感谢您留个赞.
传送门: Github
(Github上的 readme 并没有更新,看这里就行.)
未完待续:
*下一版计划在分页条上增加一个按钮的显示方式,一个图标一个标题这样子.
结尾:
- 如果发现bug和什么任何问题,请与我联系。
- 有好的意见或建议,可以联系我。