【iOS】仿喜马拉雅首页背景颜色渐变效果

前言

之前公司要求实现喜马拉雅的首页背景颜色渐变效果,于是花了一段时间实现了出来,在这里记录下,实现该效果主要用到了下面两个库:
JXCategoryView一个功能强大的分类控件
GKCycleScrollView我自己写的一个轮播图控件

效果图

先来看下效果图:


xmly.gif

说明

通过研究喜马拉雅首页你会发现,要实现该功能有三个地方需要注意
1、轮播图的滑动(左右滑动背景颜色根据图片渐变)
2、分类切换页面(两个页面的当前背景色渐变)
3、页面上下滑动(滑动到临界位置后背景色不再根据轮播图变化)
下面来说明下实现过程
JXCategoryView里面有个方法,传入两个颜色及渐变百分比,返回对应的渐变颜色,这里直接用这个方法实现渐变

1、轮播图滑动

轮播图用的GKCycleScrollView,需要监听UIScrollView的滑动,根据滑动的距离和方向,计算出当前图片和下一张图片以及渐变百分比,下面看下具体代码:

// 滑动渐变背景色
- (void)cycleScrollView:(GKCycleScrollView *)cycleScrollView didScroll:(UIScrollView *)scrollView {
    if (self.isCriticalPoint) return;
    
    CGFloat offsetX = scrollView.contentOffset.x;
    CGFloat maxW = self.bannerLists.count * scrollView.bounds.size.width;
    
    CGFloat changeOffsetX = offsetX - maxW;
    
    BOOL isFirstRight = NO;
    
    if (changeOffsetX < 0) {
        changeOffsetX = -changeOffsetX;
        isFirstRight = YES;
    }
    
    CGFloat ratio = (changeOffsetX / scrollView.bounds.size.width);
    
    // 超过了边界,不需要处理
    if (ratio > self.bannerLists.count || ratio < 0) return;
    
    ratio = MAX(0, MIN(self.bannerLists.count, ratio));
    
    NSInteger baseIndex = floorf(ratio);
    
    // 最后一个
    if (baseIndex + 1 > self.bannerLists.count) {
        baseIndex = 0;
    }
    
    CGFloat remainderRatio = ratio - baseIndex;
    if (remainderRatio <= 0 || remainderRatio >= 1) return;
    
    GKHomeBannerModel *leftModel  = self.bannerLists[baseIndex];
    
    NSInteger nextIndex = 0;
    if (isFirstRight) {
        nextIndex = self.bannerLists.count - 1;
    }else if (baseIndex == self.bannerLists.count - 1) {
        nextIndex = 0;
    }else {
        nextIndex = baseIndex + 1;
    }
    
    GKHomeBannerModel *rightModel = self.bannerLists[nextIndex];
    
    UIColor *leftColor  = leftModel.headerBgColor ? leftModel.headerBgColor : GKHomeBGColor;
    UIColor *rightColor = rightModel.headerBgColor ? rightModel.headerBgColor : GKHomeBGColor;
    
    UIColor *color = [JXCategoryFactory interpolationColorFrom:leftColor to:rightColor percent:remainderRatio];
    
    self.bgColor = color;
    
    if (self.isSelected && [self.delegate respondsToSelector:@selector(listVC:didChangeColor:)]) {
        [self.delegate listVC:self didChangeColor:color];
    }
}
2、分类切换页面

监听JXCategoryView的delegate方法,根据滑动距离找出当前页面和下一个页面及滑动百分比,渐变背景颜色

- (void)categoryView:(JXCategoryBaseView *)categoryView scrollingFromLeftIndex:(NSInteger)leftIndex toRightIndex:(NSInteger)rightIndex ratio:(CGFloat)ratio {
    
    GKListViewController *leftVC  = (GKListViewController *)self.containerView.validListDict[@(leftIndex)];
    GKListViewController *rightVC = (GKListViewController *)self.containerView.validListDict[@(rightIndex)];
    
    UIColor *leftColor  = leftVC.isCriticalPoint ? [UIColor whiteColor] : leftVC.bgColor;
    UIColor *rightColor = rightVC.isCriticalPoint ? [UIColor whiteColor] : rightVC.bgColor;
    
    UIColor *color = [JXCategoryFactory interpolationColorFrom:leftColor to:rightColor percent:ratio];
    
    self.headerBgView.backgroundColor = color;
    
    // 两边状态一样,不用改变
    if (leftVC.isCriticalPoint == rightVC.isCriticalPoint) return;
    
    if (leftVC.isCriticalPoint) {
        if (ratio > 0.5) {
            [self changeToWhiteStateAtVC:nil];
        }else {
            [self changeToBlackStateAtVC:nil];
        }
    }else if (rightVC.isCriticalPoint) {
        if (ratio > 0.5) {
            [self changeToBlackStateAtVC:nil];
        }else {
            [self changeToWhiteStateAtVC:nil];
        }
    }
}
3、页面上下滑动

监听列表的上下滑动,根据滑动距离判断是否到底临界点,改变分类的背景色

- (void)listVC:(GKListViewController *)vc didScroll:(UIScrollView *)scrollView {
    if (self.style == GKHomeThemeStyleNone) return;
    
    CGFloat offsetY = scrollView.contentOffset.y;
    if (offsetY <= 0) return;
    
    if (offsetY > ADAPTATIONRATIO * 360.0f) {
        [self changeToBlackStateAtVC:vc];
    }else {
        [self changeToWhiteStateAtVC:vc];
    }
}
4、动态刷新标题颜色和指示器颜色

关于动态改变标题颜色、指示器颜色JXCategoryView并没有提供相关方法,于是通过查看相关代码,找到了下面的解决办法,通过对JXCategoryTitleView添加分类实现

- (void)refreshCellState {
    [self.dataSource enumerateObjectsUsingBlock:^(JXCategoryBaseCellModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [self reloadCellAtIndex:idx];
    }];
    
    CGRect selectedCellFrame = CGRectZero;
    JXCategoryIndicatorCellModel *selectedCellModel = nil;
    for (int i = 0; i < self.dataSource.count; i++) {
        JXCategoryIndicatorCellModel *cellModel = (JXCategoryIndicatorCellModel *)self.dataSource[i];
        cellModel.sepratorLineShowEnabled = self.isSeparatorLineShowEnabled;
        cellModel.separatorLineColor = self.separatorLineColor;
        cellModel.separatorLineSize = self.separatorLineSize;
        cellModel.backgroundViewMaskFrame = CGRectZero;
        cellModel.cellBackgroundColorGradientEnabled = self.isCellBackgroundColorGradientEnabled;
        cellModel.cellBackgroundSelectedColor = self.cellBackgroundSelectedColor;
        cellModel.cellBackgroundUnselectedColor = self.cellBackgroundUnselectedColor;
        if (i == self.dataSource.count - 1) {
            cellModel.sepratorLineShowEnabled = NO;
        }
        if (i == self.selectedIndex) {
            selectedCellModel = cellModel;
            selectedCellFrame = [self getTargetCellFrame:i];
        }
    }
    
    for (UIView<JXCategoryIndicatorProtocol> *indicator in self.indicators) {
        if (self.dataSource.count <= 0) {
            indicator.hidden = YES;
        }else {
            indicator.hidden = NO;
            JXCategoryIndicatorParamsModel *indicatorParamsModel = [[JXCategoryIndicatorParamsModel alloc] init];
            indicatorParamsModel.selectedIndex = self.selectedIndex;
            indicatorParamsModel.selectedCellFrame = selectedCellFrame;
            [indicator jx_refreshState:indicatorParamsModel];
        }
    }
}

到这里主要的功能点就已经实现了,当然还有很多细节,如果想了解,可以到github 上查阅相关代码。

最后

仿喜马拉雅首页背景颜色渐变效果很多APP都在用,如果你需要的话可以在GKXimalaya中查看
如果您觉得还不错,还请点个star,您的支持是我最大的动力。

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