美文网首页iOS常用
iOS | 实现一个循环滚动切换的视图

iOS | 实现一个循环滚动切换的视图

作者: 清無 | 来源:发表于2020-08-26 16:12 被阅读0次

    效果

    Kapture 2020-08-26 at 16.20.59.gif

    思路

    示意图1
    • 1、如图中所示,先让BlueView(下称bv)和GreenView的frame一起往上移动:bv移出view、gv移入view;
    • 2、然后让bv的frame发生变动,瞬间移动到gv的下部,然后重复步骤1;
    • 3、定义一个计数变量countIndex,不断+1,然后根据这个值调整bv和gv的frame;
    • 4、定义一个索引变量itemIndex,不断+1,取用户数据源数据进行自定义ItemView的展示;

    实现

    • DataSource协议
    @class ZHLLoopScrollView;
    @protocol ZHLLoopScrollViewDataSource <NSObject>
    
    @required
    /// 数量
    - (NSUInteger)numerOfItemsForLoopScrollView:(ZHLLoopScrollView *)loopScrollView;
    
    /// 自定义item view
    - (UIView *)viewAtIndex:(NSUInteger)index forLoopScrollView:(ZHLLoopScrollView *)loopScrollView;
    
    @end
    
    • 属性定义
    @interface ZHLLoopScrollView()
    
    #pragma mark - Views
    
    @property(nonatomic, strong)UIView *view1;
    @property(nonatomic, strong)UIView *view2;
    
    @property(nonatomic, strong)UIView *topView;
    @property(nonatomic, strong)UIView *bottomView;
    
    #pragma mark - Datas
    /// current index
    @property(nonatomic)NSUInteger itemIndex;
    @property(nonatomic)NSUInteger countIndex;
    
    @end
    
    • 滚动切换
    /// 切换下一个
    - (void)changeNextItem{
        NSUInteger count = [self.dataSource numerOfItemsForLoopScrollView:self];
        if (_itemIndex == count) {
            _itemIndex = 0;
        }
        self.topView = _countIndex%2 == 0 ? _view1 : _view2;
        self.bottomView = [_topView isEqual:_view1] ? _view2 : _view1;
        
        NSUInteger idx = _itemIndex==count ? 0 : _itemIndex;
        [self addItemViewAtIndex:idx forView:_topView];
        
        idx = (_itemIndex+1)==count ? 0 : (_itemIndex+1);
        [self addItemViewAtIndex:idx forView:_bottomView];
        
       /// 这里进行滚动动画
        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^
        {
            CGRect rect = self.bounds;
            
            /// 移出屏幕
            rect.origin.y = -CGRectGetHeight(rect);
            self.topView.frame = rect;
            
            /// 移入屏幕
            rect.origin.y = CGRectGetMaxY(rect);
            self.bottomView.frame = rect;
        } completion:^(BOOL finished)
        {
            CGRect rect = self.bounds;
            
            /// 移出屏幕
            rect.origin.y = CGRectGetHeight(rect);
            self.topView.frame = rect;
            
            /// 下一个
            [self performSelector:@selector(changeNextItem) withObject:nil afterDelay:self.scrollDuration-0.3];
        }];
        
        _itemIndex += 1;
        _countIndex += 1;
    }
    
    • 数据刷新
    - (void)reloadData{
        /// 清零
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
        _countIndex = 0;
        _itemIndex = 0;
        [_view1.layer removeAllAnimations];
        [_view2.layer removeAllAnimations];
        [_view1 removeFromSuperview];
        [_view2 removeFromSuperview];
        _view1 = nil;
        _view2 = nil;
        
        NSUInteger count = [_dataSource numerOfItemsForLoopScrollView:self];
        if (count > 0) {
            [self addSubview:self.view1];
            [self addItemViewAtIndex:0 forView:_view1];
        }
        if (count > 1) {
            [self addSubview:self.view2];
            [self addItemViewAtIndex:1 forView:_view2];
            
            [self performSelector:@selector(changeNextItem) withObject:nil afterDelay:_scrollDuration-0.3];
        }
    }
    
    • item view展示
    /// 构建item视图
    - (void)addItemViewAtIndex:(NSUInteger)index forView:(UIView *)view{
        [view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
        
        UIView *v = [self.dataSource viewAtIndex:index forLoopScrollView:self];
        v.frame = view.bounds;
        v.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
       
    
    • Getters
    /// view1
    - (UIView *)view1{
        if (!_view1) {
            _view1 = [[UIView alloc] initWithFrame:self.bounds];
            _view1.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
        }
        return _view1;
    }
    
    /// view2
    - (UIView *)view2{
        if (!_view2) {
            CGRect rect = self.view1.frame;
            rect.origin.y = CGRectGetMaxY(rect);
            
            _view2 = [[UIView alloc] initWithFrame:rect];
            _view2.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
        }
        return _view2;
    }
    

    使用

    • 初始化
        CGRect rect = self.view.bounds;
        rect.size.height = 60;
        rect.origin.y = 200;
    /// 这里也支持xib方式
        ZHLLoopScrollView *v = [[ZHLLoopScrollView alloc] initWithFrame:rect];
        v.dataSource = self;
        v.scrollDuration = 1.5;
        [self.view addSubview:v];
    /// 这里也可以放在数据request的异步里
        [v reloadData];
    
    • 数据源
    - (NSUInteger)numerOfItemsForLoopScrollView:(ZHLLoopScrollView *)loopScrollView{
        return 5;
    }
    
    - (UIView *)viewAtIndex:(NSUInteger)index forLoopScrollView:(ZHLLoopScrollView *)loopScrollView{
    /// 这是用户自定义的UIView,这里自行进行数据展示
        LoopItemView *v = [LoopItemView view];
        v.textLb.text = [@"这是直播: " stringByAppendingString:@(index).stringValue];
        return v;
    }
    

    源码

    https://github.com/BackWorld/ZHLLoopScrollView

    相关文章

      网友评论

        本文标题:iOS | 实现一个循环滚动切换的视图

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