美文网首页iOSiOSView
UITableView的嵌套+左右侧滑选项卡的头部悬停

UITableView的嵌套+左右侧滑选项卡的头部悬停

作者: 请叫我魔法师 | 来源:发表于2017-10-21 16:31 被阅读424次

    PS:也是看别人写的。自己刚好有这个需求,看了代码,改吧改吧就用了。找不到那篇文章了。

    效果:实现tableview的嵌套,页面可以左右滑动切换页面。头部轮播图隐藏的时候,选项卡实现头部悬停的效果。如下:


    滑动效果.gif

    分析过程:
    1.看到可以上下滑动,并带有头view,立马想到是最外层是UITableView
    2.三个按钮的选项卡可以悬停到头部,立马想到是sectionHeader,tableview用plain样式。更加确定是最外层用tableview做的。
    3.可以滑动,这种样式是scrollview或者collectionview上添加tableview

    所以,层级关系是tableview-->collectionview-->tableview

    开始也想着根据偏移量,打开或者关闭用户交互,设置偏移量啥的,试了试,发现效果太差,后来上网搜了,找了别人的方法,看着代码,自己试了试,能达到我需要的效果。自己看明白了,就挪到自己项目里了。

    其实全篇看下来,主要是通过一个全局的BOOL值,设置tableview是否需要滑动,在scrollview的代理方法里,根据tableview的偏移量,再结合这个BOOL值,判断是否需要滑动,同时设置tableview的偏移量。

    一、最外层tableview

    1.上下滑动的tableview

    由于屏幕上有多个tableview,需要同时相应操作,所以这个tableview需要接受多个手势。需要新建一个tableview,继承自UITableView,遵守手势代理,运行接受多个手势。暂时称为大tableview,有个canScroll属性。
    h文件

    #import <UIKit/UIKit.h>
    
    @interface MainTableView : UITableView <UIGestureRecognizerDelegate>
    
    @end
    

    m文件

    #import "MainTableView.h"
    
    @implementation MainTableView
    
    //允许接受多个手势
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
        
        return YES;
    }
    
    @end
    

    还需要headView,sectionHeaderView等。

    2.横向滑动的collectionview

    由于最外层的tableview只起到上下滑动的作用,所以一个cell就够了。
    cell的高度 = 屏幕高度 - 头view高度 - sectionHeader高度。
    在这个cell上添加一个collectionview,横向滑动,collectionview大小和cell大小一致。
    紧接着在这个collectionview上添加几个tableview,这几个tableview大小和collectionview大小一致,即和最外层唯一的大cell的大小一致。暂时称为小tableview.也有个canScroll属性。
    添加小tableview的时候,用了addChildViewController方法,等于先添加子控制器,用了子控制器的tableview。

        self.subVC1 = [[SubTableVC alloc] init];
        [self addChildViewController:self.subVC1];
    
    -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"UICollectionViewCellID" forIndexPath:indexPath];
        cell.backgroundColor = [UIColor yellowColor];
        
        SubTableVC *subVC = self.childViewControllers[indexPath.row];
        subVC.view.frame = CGRectMake(0, 0, SCREENW, SCREENH-64-49-40);
        subVC.tableView.frame = CGRectMake(0, 0, SCREENW, SCREENH-64-49-40);
        [cell.contentView addSubview:subVC.view];
        return cell;
    }
    

    这样就完成了整体的结构。

    三、监听tableview的偏移量

    直接根据scollview的代理方法,- (void)scrollViewDidScroll:(UIScrollView *)scrollView;监听大tableview的滑动。

    这里是重点。慢慢滑动页面,慢慢体会。

    大tableview的滑动:

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        
        if (scrollView == self.tableView) {
         
            CGFloat scrollY = [self.tableView rectForSection:0].origin.y;
            
            if (scrollView.contentOffset.y >= scrollY) {
                
                if (self.canScroll == YES) {
                    
                    self.canScroll = NO;
                    
                    self.subVC1.canScroll = YES;
                    self.subVC1.tableView.contentOffset = CGPointZero;
                    self.subVC2.canScroll = YES;
                    self.subVC2.tableView.contentOffset = CGPointZero;
                    self.subVC3.canScroll = YES;
                    self.subVC3.tableView.contentOffset = CGPointZero;
                }
                
                self.tableView.contentOffset = CGPointMake(0, scrollY);
                
            }else{
                //这句判断,是在小tableview往滑动的时候,需要固定大tableview的偏移量,原因参考第6点。
                if (self.canScroll == NO) {
                    self.tableView.contentOffset = CGPointMake(0, scrollY);
                }
            }
        }
    }
    

    过程分析:
    1.根据实际需求,首次加载页面的时候,大tableview需要滑动,小tableview不需要滑动,这个时候是大tableview带着小tableview跑。所以大tableview的canScroll=YES,小tableview的canScroll=NO。两者的属性值一直是相反的。实际情况也只这样 ,滑动的时候,只需要一个滑动就够了。

    2.等滑动头view消失的时候,大tableview就不需要滑动,小tableview滑动。
    (scrollY是头tableview中第一个section的Y坐标。也就是头view需要消失的时候的偏移量)。

    3.第一次向下滑动,从大tableview下滑动开始,直到头view消失之前,这个时间段这个代理方法不需要啥操作,这段时间是大tableview带着小tableview滑动。

    4.等第一次滑动偏移量=scrollY的时候,,这个时候大tableview就不需要滑动了,该小tableview滑动了。所以这时候需要if (scrollView.contentOffset.y >= scrollY)这个判断开始起作用。

    5.继续往下滑,都是小tableview在滑动了。看起来貌似没大tableview的事情了。接着就网上滑动了,需要回去了。

    6.重点:虽然canScroll属性=NO,但不代表大小tableview不会滑动了,它每时每刻都在响应着scrollview的代理方法。它还会滑动,只是我们不让它滑动,不需要滑动的时候,我们就固定它的偏移量。(这点很重要)

    小tableview滑动的监听
    block是为了通知大tableview可以滑动了。

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        
        if (self.canScroll == NO) {
            scrollView.contentOffset = CGPointZero;
        }
        
        if (scrollView.contentOffset.y < 0 ) {
            self.canScroll = NO;
            scrollView.contentOffset = CGPointZero;
            self.block();
        }
    }
    

    7.页面初始化canScroll=NO,所以为了不让它滑动,就设置偏移量=0,等到可以滑动的时候,canScroll=YES。

    8.该往上滑回到顶部了。第6点说过,tableview一直响应滑动的方法,所以一直网上滑,当scrollView.contentOffset.y < 0,说明小tableview到顶部了,就不需要它滑动了,设置canScroll=NO,通知大tableview可以滑动了。

    9.在block通知中设置大tableview canScroll=YES,回到了初始状态,完成了整个过程。
    demo

    相关文章

      网友评论

      本文标题:UITableView的嵌套+左右侧滑选项卡的头部悬停

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