美文网首页程序员
iOS笔记之实现新闻类客户端顶部的滚动效果

iOS笔记之实现新闻类客户端顶部的滚动效果

作者: SuAdrenine | 来源:发表于2018-01-09 20:47 被阅读565次

    1.写在前面:

    前段时间项目用到了类似新闻类客户端顶部的滚动条,虽然网上也有很多,但是本着锻炼自己的想法,自己动手写了一个,所幸效果不差,遂分享出来,一方面给大家参考,一方面也给自己记录。

    上效果图:


    效果

    2.使用方法:

    方法1:

    NSArray *titleArray = @[@"推荐",@"热点",@"视频",@"体育",@"搞笑"];
    NSMutableArray *vcArray = @[].mutableCopy;
    for (int i = 0; i<titleArray.count; i++) {
        ViewController *vc = [ViewController new];
        [vcArray addObject:vc];
    }
    XBYTopTabBarViewController *tabVC = [[XBYTopTabBarViewController alloc] initWithSegmentTitles:titleArray childVcs:vcArray];
    [self.navigationController pushViewController:tabVC animated:YES];
    

    方法2:(推荐使用)

    //新建ViewController继承XBYTopTabBarViewController,改写init方法
    - (instancetype)init {
        if (self = [super init]) {
            NSArray *tabNames = @[@"推荐",@"热点",@"视频",@"体育",@"搞笑"];
    
            NSMutableArray *vcs = @[].mutableCopy;
            for (NSString *name in tabNames) {
                ViewController *vc = [[ViewController alloc]init];
                [vcs addObject:vc];
            }
            self = [super initWithSegmentTitles:tabNames childVcs:vcs];
        }
    
        return self;
    }
    
    

    这里是封装的是一个ViewController,网上很多封装的都是view,需要一系列配置,我觉得比较麻烦,还是继承来的快一些,继承XBYTopTabBarViewController以后,有多少个子项新建多个vc,调用

    - (instancetype)initWithSegmentTitles:(NSArray *)titles
                                 childVcs:(NSArray *)childVcs;
    

    方法,这里继承的vc和众多子vc的生命周期都已经设置好了,可以不用管了,只需要继承(懒一点继承也不要了,直接调用上面这个方法),其他的都不用管了。

    3.实现思路:

    这里用到了两个scrollView
    上面title一栏是一个scrollView(这里也可以用其他view,这个scrollView不需要左右滑动,但是需要响应点击事件),后面用smallScrollView,下面可以左右滑动的部分也是一个scrollView,后面用bigScrollView表示。
    有多少个滑动项,就新建多少个label添加到smallScrollView里面:

    - (void)setupSmallScrollView {
        CGFloat labelW = kScreenWidth/(self.segmentTitles.count>5?5:self.segmentTitles.count);
        self.smallScrollView.contentSize = CGSizeMake(labelW * self.segmentTitles.count, 44);
        
        CGFloat labelX,labelY = 0, labelH = smallScrollViewH;
        for (int i = 0; i < self.segmentTitles.count; i++) {
            labelX = i * labelW;
            GGSOrderStatusLabel *label = [[GGSOrderStatusLabel alloc]initWithFrame:CGRectMake(labelX, labelY, labelW, labelH)];
            label.text = self.segmentTitles[i];
            label.tag = i;
            label.userInteractionEnabled = YES;
            [label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(labelTapAction:)]];
            [self.smallScrollView addSubview:label];
        }
    }
    

    给label添加手势,响应点击事件,同时让bigScrollView跟随点击的smallScrollView的子项联动:

    - (void)labelTapAction:(UITapGestureRecognizer *)gesture {
        GGSOrderStatusLabel *titlelable = (GGSOrderStatusLabel *)gesture.view;
        if (titlelable.tag == _currentIndex) {
            return;
        }
        
        CGFloat offsetX = titlelable.tag * self.bigScrollView.frame.size.width;
        
        CGFloat offsetY = self.bigScrollView.contentOffset.y;
        CGPoint offset = CGPointMake(offsetX, offsetY);
        
        [self.bigScrollView setContentOffset:offset animated:YES];  //点击smallScrollView的label项,bigScrollView要联动,同时滚动。
        
    }
    

    实现bigScrollView的代理,让smallScrollView跟随它联动:

    /** 滚动结束后调用 */
    - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
        // 获得索引
        NSUInteger index = scrollView.contentOffset.x / self.bigScrollView.frame.size.width;
        
        // 滚动标题栏
        GGSOrderStatusLabel *titleLable = (GGSOrderStatusLabel *)self.smallScrollView.subviews[index];
        // label居中的offsetx
        CGFloat offsetx = titleLable.center.x - self.smallScrollView.frame.size.width * 0.5;
        CGFloat offsetMax = self.smallScrollView.contentSize.width - self.smallScrollView.frame.size.width;
        if (offsetx < 0) {
            offsetx = 0;
        }else if (offsetx > offsetMax){
            offsetx = offsetMax;
        }
        CGPoint offset = CGPointMake(offsetx, self.smallScrollView.contentOffset.y);
        // 要放在gcd里才有动画
        dispatch_async(GCD_MAINQUEUE, ^{
            [self.smallScrollView setContentOffset:offset animated:YES];
        });
        
        UIViewController *oldVC = nil;
        if (_currentIndex != -1) {
            oldVC = self.childVcs[_currentIndex];
        }
        
        UIViewController *newsVc = self.childVcs[index];
        self.currentIndex = index;
        // 其他label设置成初始状态
        [self.smallScrollView.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            if (idx != index) {
                GGSOrderStatusLabel *temlabel = self.smallScrollView.subviews[idx];
                temlabel.scale = 0.0;
            }
        }];
        
        if (newsVc.view.superview)  {//调用生命周期函数(如viewwillappear等)
            if (oldVC) {
                [newsVc beginAppearanceTransition:NO animated:YES];
                [newsVc endAppearanceTransition];
            }
            
            [newsVc beginAppearanceTransition:YES animated:YES];
            [newsVc endAppearanceTransition];
            return;
        }
        
        [self addChildViewController:newsVc];
        newsVc.view.frame = scrollView.bounds;//bounds的x就是scrollView的offsetx
        [self.bigScrollView addSubview:newsVc.view];
        [newsVc didMoveToParentViewController:self];
        
        if ([self.delegate respondsToSelector:@selector(segmentViewController:didAddChildViewController:)]) {
            [self.delegate segmentViewController:self didAddChildViewController:newsVc];
        }
    }
    

    3.其他

    见下面头文件描述:

    @protocol XBYTopTabBarViewControllerDelegate <NSObject>
    
    @optional
    - (void)topTabBarViewController:(XBYTopTabBarViewController *)topTabBarVC
    didAddChildViewController:(UIViewController *)childVC;
    
    @end
    
    @interface XBYTopTabBarViewController : UIViewController
    
    /**
    上面滑块的标题
    */
    @property (nonatomic, strong, readonly) NSArray *segmentTitles;
    
    /**
    一个滑块对应一个viewController
    */
    @property (nonatomic, strong, readonly) NSMutableArray *childVcs;
    
    /**
    当前滑块的index
    */
    @property (nonatomic, assign) NSInteger currentIndex;
    
    /**
    用于存放滑块的scrollView
    */
    @property (nonatomic, strong) UIScrollView *smallScrollView;
    
    /**
    用于存放viewController的scrollView
    */
    @property (nonatomic, strong) UIScrollView *bigScrollView;
    
    @property (nonatomic, weak) id<XBYTopTabBarViewControllerDelegate> delegate;
    
    /**
    <#Description#>
    
    @param titles 滑块标题数组
    @param childVcs 滑块对应的viewController数组
    @return <#return value description#>
    */
    - (instancetype)initWithSegmentTitles:(NSArray *)titles
    childVcs:(NSArray *)childVcs;
    
    

    4.联系方式

    5.Demo:

    XBYTopTabBarViewController

    相关文章

      网友评论

        本文标题:iOS笔记之实现新闻类客户端顶部的滚动效果

        本文链接:https://www.haomeiwen.com/subject/ynwgnxtx.html