UIScrollView嵌套UIScrollView、UITableView、UICollectionView的滚动处理

2021-01-12 22:19:08

参考链接 UIScrollView嵌套UIScrollView、UITableView、UICollectionView的滚动处理

1、为了展示嵌套效果,适配复杂布局内部采用了三个子ViewController:

FirstViewController 内部为TableView布局
SecondScrollViewController 内部为ScrollView布局
ThirdViewController 为CollectionView 布局

2、FirstViewController、SecondScrollViewController、ThirdViewController分别实现了NestedDelegate接口:

@protocol NestedDelegate <NSObject>
-(UIScrollView *)getNestedScrollView;
@end

3、ViewController中通过NestedDelegate获取到子类的UIScrollView,通过KVO监听UIScrollView->contentOffset的变化:

    [_currentNestedDelegate.getNestedScrollView  addObserver:self forKeyPath:kObseverKeyContentOffset options:NSKeyValueObservingOptionNew context:nil];

(这里需要注意,切不可在ViewController中给_currentNestedDelegate.getNestedScrollView设置滚动的代理,设置了会形成循环引用导致crash)

4、滚动处理的核心代码:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    //最大上滑距离
    CGFloat maxOffset = _layoutHeaderViewHeight.constant;
    CGFloat mainContentOffsetY = _mainScrollView.contentOffset.y;
    
    if (scrollView == _mainScrollView) {
        if (mainContentOffsetY > maxOffset) {
            [_mainScrollView setContentOffset:CGPointMake(0, maxOffset)];
        }else if(mainContentOffsetY < 0){
            [_mainScrollView setContentOffset:CGPointMake(0, 0)];
        }
    }else if (scrollView == _currentNestedDelegate.getNestedScrollView){
        UIScrollView *currentScrollView = _currentNestedDelegate.getNestedScrollView;
        CGFloat currentOffsetY = currentScrollView.contentOffset.y;
        //避免死循环
        if (currentOffsetY == 0) {
            return;
        }
        
        if(currentOffsetY < 0){
            //下滑
            if(mainContentOffsetY > 0){
              //将子scrollview的滑动距离赋值给mainScrollView
                [_mainScrollView setContentOffset:CGPointMake(0, mainContentOffsetY+currentOffsetY)];
                //重置子scrollview的offset
                [currentScrollView setContentOffset:CGPointMake(0, 0)];
            }
        }else if(currentOffsetY >0){
            //上拉
            if(mainContentOffsetY < maxOffset){
              //将子scrollview的滑动距离赋值给mainScrollView
                [_mainScrollView setContentOffset:CGPointMake(0, mainContentOffsetY+currentOffsetY)];
                //重置子scrollview的offset
                [currentScrollView setContentOffset:CGPointMake(0, 0)];
            }
        }
    }}

1、嵌套UITableView效果


嵌套UITableView效果.gif

2、嵌套UIScrollView效果


嵌套UIScrollView效果.gif

3、嵌套UICollectionView效果


“嵌套UICollectionView效果.gif



1、源码地址

  • 2020-02-25 19:24:08

    IDEA 简单的正则匹配

    IDEA在进行查看或替换的时候,勾选Regex 选项就可以进行正则匹配查找了 几个简单实用的正则:

  • 2020-02-26 20:16:49

    一条简单的命令就可以将 stylus 语法转换为 scss 语法

    因为早期有个项目用到了 stylus,stylus 开发起来很爽,但 stylus 基于缩进的代码在修改的时候不是很方便,加上所在团队开发使用的都是 SCSS ,为了便于维护和统一,准备将项目中的 stylus 替换成 SCSS。手动转换 stylus 浪费时间,且出错率大,当时在想也许别人也有这样的需求呢,所以就做了这样一个项目。请各位大佬动动你们发财的小手,给我点个 star,不胜感激。^_^

  • 2020-02-27 09:01:32

    npm yarn 命令对比

    Yarn 是 Facebook, Google, Exponent 和 Tilde 开发的一款新的 JavaScript 包管理工具。就像我们可以从官方文档了解那样,它的目的是解决这些团队使用 npm 面临的少数问题.

  • 2020-02-29 20:47:34

    Nuxt 特有函数和变量

    asyncData方法使得你能够在渲染组件之前异步获取数据。该方法在服务端中执行的,所以,请求数据时,不存在跨域问题。返回的数据将与 data() 返回的数据进行合并。由于asyncData方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象。

  • 2020-03-01 19:00:46

    触发onclick事件元素的获取

    自动生成元素的onclick事件 event.target返回触发事件的元素 event.currentTarget返回绑定事件的元素