preface

Before the company required to implement the himalaya home page background color gradient effect, so it took some time to implement it, here is a record, to achieve this effect mainly using the following two libraries: JXCategoryView a powerful classification control GKCycleScrollView A wheel map control written by me

rendering

Take a look at the renderings first:

instructions

If you look at the Front page of the Himalayas, There are three places need to pay attention to in order to realize the function, the wheels of sliding of the figure 1 (left and right sliding background color gradient according to the pictures) 2, classification switch page (two pages of the current background color gradient) 3, page up and down slide (slide to the critical position back the scenery is no longer based on shuffling figure change) below to illustrate the implementation process There is a method in JXCategoryView that passes in two colors and a gradient percentage, and returns the corresponding gradient color

1. Rotation map sliding

According to the sliding distance and direction, calculate the current picture and the next picture as well as the gradient percentage. See the specific code below:

// slide gradient background color - (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); // There is no need to handle itif (ratio > self.bannerLists.count || ratio < 0) return; ratio = MAX(0, MIN(self.bannerLists.count, ratio)); NSInteger baseIndex = floorf(ratio); // The last oneif (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]; }}Copy the code
2. Classification switching page

Listen to the Delegate method of the JXCategoryView and gradient the background color based on the slide distance to find the current page and the next page and the slide percentage

- (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; // Both states are the same, do not changeif (leftVC.isCriticalPoint == rightVC.isCriticalPoint) return;
    
    if (leftVC.isCriticalPoint) {
        ifThewire (0.5) > {[self changeToWhiteStateAtVC: nil]; }else{ [self changeToBlackStateAtVC:nil]; }}else if (rightVC.isCriticalPoint) {
        ifThewire (0.5) > {[self changeToBlackStateAtVC: nil]; }else{ [self changeToWhiteStateAtVC:nil]; }}}Copy the code
3. Slide the page up and down

Listen to the list of sliding up and down, according to the sliding distance to judge whether the critical point, change the classification background color

- (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.0 f) {[self changeToBlackStateAtVC: vc]; }else{ [self changeToWhiteStateAtVC:vc]; }}Copy the code
4. Dynamically refresh the title and indicator colors

JXCategoryView does not provide a way to dynamically change the title color and indicator color, so by looking at the code, I found the following solution by adding categories to the 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]; }}}Copy the code

The main feature points are already there, but there are many more details. You can check out the code on Github for more details.

The last

Many apps are used to simulate the background color gradient effect of Himalaya home page. If you need it, you can check it in GKXimalaya. If you think it is good, please click star.

appreciates

Your appreciation is my greatest support