iOS 开发手把手教你封装一个高大上的多页面控制器,2018-04-07

前言:

        小鹿哥最近又接到新的任务了,就是在分析需求的时候,我们要按照多个科目的班次对课程进行分类,那么多的课程怎么分类好呢;我们的主要目的就是让用户看了后能清晰明了的知道我们有哪些课程,这些课程分别是属于哪个科目的,然后结合自己的情况进行线上支付并购买。我们讨论了一下就决定对科目以及课程班次进行多页面控制,下面我就从技术的角度来实现这个功能。

1、两个collectionView,一个用作“表头”,一个用作“表身”。因为collectionView是复用collectionViewCell的自带内存回收机制,所以使用起来更加流畅,更加节省内存,所以小鹿哥比较推荐使用这种实现方式。

2、实现两个collectionView的布局:(titleCollectionView代表title容器,mainCollectionView代表控制器容器)

******首先是对titleCollectionView进行布局:******

-(UICollectionView *)titleCollectionView{

    if (!_titleCollectionView) {

        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];

        layout.scrollDirection        = UICollectionViewScrollDirectionHorizontal;

        layout.minimumInteritemSpacing = 0;

        layout.minimumLineSpacing      = 0;

        layout.sectionInset            = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0);

        layout.minimumLineSpacing      = 5*SizeScale;//每行的间距)


        _titleCollectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 64, WIDTH, 50)collectionViewLayout:layout];

        if (ScreenWidth == 375 && ScreenHeight != 812) {

            _titleCollectionView.frame = CGRectMake(0, 64, WIDTH, 44);

        } else if (ScreenHeight == 812) {

            _titleCollectionView.frame = CGRectMake(0, 84, WIDTH, 44);

        } else if (ScreenWidth == 320) {

            _titleCollectionView.frame = CGRectMake(0, 64, WIDTH, 44);

        }

        _titleCollectionView.backgroundColor=[UIColor whiteColor];

        _titleCollectionView.delegate      = self;

        _titleCollectionView.dataSource    = self;

        _titleCollectionView.pagingEnabled = NO;

        _titleCollectionView.bounces      = YES;

        _titleCollectionView.showsHorizontalScrollIndicator = NO;

        _titleCollectionView.scrollsToTop  = NO;

        _titleCollectionView.scrollEnabled = YES;

        [_titleCollectionView registerNib:[UINib nibWithNibName:@"SKHomeTitleCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:cellId];

    }

    return _titleCollectionView;

}

******然后是对mainCollectionView进行布局:******

-(UICollectionView *)mainCollectionView{

    if (!_mainCollectionView) {

        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];

        layout.scrollDirection            = UICollectionViewScrollDirectionHorizontal;

        layout.minimumInteritemSpacing    = 0;

        layout.minimumLineSpacing          = 0;

        layout.sectionInset                = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0);

        layout.minimumLineSpacing        = 0;//每行的间距)


        _mainCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 64+50, WIDTH, HEIGHT-114 - 49)collectionViewLayout:layout];

        if (ScreenWidth == 375 && ScreenHeight != 812) {

            _mainCollectionView.frame = CGRectMake(0, 64+44, WIDTH, HEIGHT-108 - 49);

        } else if (ScreenHeight == 812) {

            _mainCollectionView.frame = CGRectMake(0, 88+44, WIDTH, HEIGHT-132 - 49 - 34);

        } else if (ScreenWidth == 320) {

            _mainCollectionView.frame = CGRectMake(0, 64+44, WIDTH, HEIGHT-108 - 49);

        }

        layout.itemSize = _mainCollectionView.frame.size;

        _mainCollectionView.backgroundColor = [UIColor whiteColor];

        _mainCollectionView.delegate        = self;

        _mainCollectionView.dataSource      = self;

        _mainCollectionView.pagingEnabled  = YES;

        _mainCollectionView.bounces        = NO;

        _mainCollectionView.showsHorizontalScrollIndicator = NO;

        _mainCollectionView.scrollsToTop    = NO;

        _mainCollectionView.scrollEnabled  = YES;

        [_mainCollectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"collectionMain"];


    }

    return _mainCollectionView;

}

******每个科目都带有一个下划线会随着标题的选择而移动我们把他添加在mainCollectionView上:******

[self.titleCollectionView addSubview:self.selectLineView]; 

- (UIView *)selectLineView {

    if (!_selectLineView) {

        _selectLineView = [[UIView alloc] init];

        _selectLineView.backgroundColor = [UIColor colorWithHexString:@"007aff"];

    }

    return _selectLineView;

}

******其中有一个重要的变量来标记当前的titleCollectionView所选中的是哪一节课程我们定义为currentDex,当拖动mainCollectionView或者点击titleCollectionView的时候他的值都会随之变化,我们根据这个currentDex来确定当前选中的控制器,以及确定下划线selectLineView的布局******

- (void)layoutSubview {


    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentDex inSection:0];

    //设置选中偏移量

    CGFloat itemCenterX = [self getCenterXWithRow:indexPath.row];

    //设置底部红线

    CGSize size = [self collectionView:self.titleCollectionView sizeForItemAtIndexPath:indexPath];

    self.selectLineView.frame = CGRectMake(0, 0, size.width, 2);

    self.selectLineView.center = CGPointMake(itemCenterX, self.titleCollectionView.frame.size.height - 8);

}

-(CGFloat)getCenterXWithRow:(NSInteger)row

{

    if (row<0) {row=0;}

    if (row>=[self.btnTitleArray count]) {row = [self.btnTitleArray count]-1;}

    UICollectionViewLayoutAttributes * att = [self.titleCollectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0]];

    return att.center.x;

}

- (CGSize)collectionView:(UICollectionView *)collectionView sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    if (collectionView == self.titleCollectionView) {

        SKHomeBaseTitle *model=self.btnTitleArray[indexPath.row];

        NSString * keyWords = model.titleStr;

        CGSize size = [keyWords sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14 * SizeScale]}];

        CGFloat itemWidth = size.width-10;

        CGFloat itemHeight = self.titleCollectionView.frame.size.height;

        return CGSizeMake(itemWidth, itemHeight);

    }

    if (collectionView==self.mainCollectionView) {

        return collectionView.frame.size;

    }

    return CGSizeZero;

}

******确定科目的数量:******

NSArray *arr=@[@{@"name":@"法考(司考)",@"grouptypeid":@"1"},@{@"name":@"法律硕士",@"grouptypeid":@"4"},@{@"name":@"初级会计",@"grouptypeid":@"8"},@{@"name":@"中级会计",@"grouptypeid":@"9"},@{@"name":@"高级会计",@"grouptypeid":@"1"}]; 

for (int p=0; p<arr.count;p++){

NSDictionary *classDic = [arr objectAtIndex:p];

SKHomeBaseTitle *titleModel = [[SKHomeBaseTitle alloc]init];

                        if (p == 0) {

                            titleModel.orSelect=YES;

                        } else {

                            titleModel.orSelect=NO;

                        }

                        titleModel.titleStr=[classDic objectForKey:@"name"];

                        titleModel.grouptypeid = [classDic objectForKey:@"grouptypeid"];

                        [self.btnTitleArray  addObject:titleModel];

}

[self.titleCollectionView reloadData];

其中的btnTitleArray就是存放的标题数据来源。

***初始化需要的视图控制器:***

- (void)getTitleData{

[self.vcArray removeAllObjects];

    [self  removeAllChildViewControllers ];

for (int i =0; I<self.btnTitleArray.count; I++){

if (i==0) {

            S_FaKaoViewController *vc=[[S_FaKaoViewController alloc] init];

            SKHomeBaseTitle *model = self.btnTitleArray[i];

            [vc didMoveToParentViewController:self];

            vc.labelNameStr=model.titleStr;

            vc.grouptypeid=model.grouptypeid;

            [self.vcArray addObject:vc];

            [self addChildViewController:vc];

        } else if (i==1) {

            S_FaShuoViewController *vc=[[S_FaShuoViewController alloc] init];

            SKHomeBaseTitle *model = self.btnTitleArray[i];

            [vc didMoveToParentViewController:self];

            vc.labelNameStr=model.titleStr;

            vc.grouptypeid=model.grouptypeid;

            [ self.vcArray addObject:vc];

            [self addChildViewController:vc];

        } else if (i==2) {

            S_JuniorViewController *vc=[[S_JuniorViewController alloc] init];

            SKHomeBaseTitle *model = self.btnTitleArray[i];

            [vc didMoveToParentViewController:self];

            vc.labelNameStr=model.titleStr;

            vc.grouptypeid=model.grouptypeid;

            [self.vcArray addObject:vc];

            [self addChildViewController:vc];

        } else if (i==3) {

            S_MiddleViewController *vc=[[S_MiddleViewController alloc] init];

            SKHomeBaseTitle *model = self.btnTitleArray[i];

            [vc didMoveToParentViewController:self];

            vc.labelNameStr=model.titleStr;

            vc.grouptypeid=model.grouptypeid;

            [ self.vcArray addObject:vc];

            [self addChildViewController:vc];

        } else {

            SameAllViewController *sameVc = [[SameAllViewController alloc] init];

            SKHomeBaseTitle *model = self.btnTitleArray[i];

            [sameVc didMoveToParentViewController:self];

            sameVc.labelNameStr=model.titleStr;

            sameVc.grouptypeid=model.grouptypeid;

            [ self.vcArray addObject:sameVc];

            [self addChildViewController:sameVc];


        }

}

[self.mainCollectionView reloadData];

    [self.titleCollectionView reloadData];

}

#pragma mark --collectionViewDelegate

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {


    if (collectionView==self.titleCollectionView) {


        SKHomeBaseTitle *model=self.btnTitleArray[indexPath.row];

        if (ScreenWidth == 375) {

            CGFloat w=[UILabel getwidthOfH:44.0f  andText:model.titleStr andFontSize:14 * SizeScale];

            return (CGSize){w+35*SizeScale,44};

        } else {

            CGFloat w=[UILabel getwidthOfH:50.0f  andText:model.titleStr andFontSize:14 * SizeScale];

            return (CGSize){w+35*SizeScale,50};

        }

    }else{

        // 需要调试下

        return (CGSize){WIDTH,HEIGHT-108};

    }

}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{

    if (collectionView ==self.titleCollectionView) {

        return _btnTitleArray.count;

    }else{

        return _btnTitleArray.count;

    }

}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{

    if (collectionView==self.titleCollectionView) {


        SKHomeTitleCollectionViewCell *cell = [self.titleCollectionView dequeueReusableCellWithReuseIdentifier:cellId forIndexPath:indexPath];

        SKHomeBaseTitle *model=self.btnTitleArray[indexPath.row];

        cell.titleBtnLabel.font = [UIFont systemFontOfSize:14 * SizeScale];

        cell.titleBtnLabel.text=model.titleStr;

        if (model.orSelect==YES) {

            cell.titleBtnLabel.textColor = [UIColor colorWithHexString:@"007aff"];

        }else{

            cell.titleBtnLabel.textColor = [UIColor colorWithHexString:@"333333"];

        }

        return cell;


    }else{

        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"collectionMain" forIndexPath:indexPath];

        for (UIView *vc in cell.contentView.subviews) {

            [vc removeFromSuperview];

        }

        UIViewController *viewC = (UIViewController *)self.vcArray[indexPath.item];

        viewC.view.frame = cell.contentView.bounds;


        [cell.contentView addSubview:viewC.view];

        return cell;


    }

}

// cell与cell之间的间隔,边距

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {


    if (collectionView == self.titleCollectionView) {

        return UIEdgeInsetsMake(0, 25, 0, 25);

    } else {

        //上左下右

        return UIEdgeInsetsMake(0, 0, 0, 0);

    }

}

这样就把两个collectionView的布局弄完了,剩下的就是处理滚动事件与点击头部事件所做的处理了。那么我们根据collectionView是集成ScrollocView的特性进行处理。

3、处理重要的页面之间交互事件:

******当页面滚动的时候******

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {


    if ([scrollView isEqual:self.mainCollectionView]) {

        int p = self.mainCollectionView.contentOffset.x/WIDTH;


        if (p==[self.btnTitleArray count]-1) {

            p--;

        }


        SKHomeTitleCollectionViewCell *indexcell = (SKHomeTitleCollectionViewCell *)[self.titleCollectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:p inSection:0]];

        CGFloat indexCenterX = [self getCenterXWithRow:p];


        NSInteger aimIndex = p+1;

        SKHomeTitleCollectionViewCell *aimcell = (SKHomeTitleCollectionViewCell *)[self.titleCollectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:aimIndex inSection:0]];

        CGFloat aimIndexCenterX = [self getCenterXWithRow:aimIndex];


        CGFloat scale = ABS(p*scrollView.width-scrollView.contentOffset.x)/scrollView.width;

        self.selectLineView.centerX = indexCenterX+(aimIndexCenterX - indexCenterX)*scale;//设置位移



        CGSize indexSize = [self collectionView:self.titleCollectionView sizeForItemAtIndexPath:[NSIndexPath indexPathForRow:p inSection:0]];

        CGSize aimIndexSize = [self collectionView:self.titleCollectionView sizeForItemAtIndexPath:[NSIndexPath indexPathForRow:aimIndex inSection:0]];

        self.selectLineView.width = (indexSize.width)+(aimIndexSize.width-indexSize.width)*scale;//设置宽度


        if (scale>0.5) {

            //            [self collectionView:self.titleCollectionView didDeselectItemAtIndexPath:[NSIndexPath indexPathForRow:p inSection:0]];


            aimcell.selected = YES;

        }else{

            //            [self collectionView:self.titleCollectionView didDeselectItemAtIndexPath:[NSIndexPath indexPathForRow:aimIndex inSection:0]];

            indexcell.selected = YES;

        }

    }

}

// 结束拖拽

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{

    if ([scrollView isEqual:self.mainCollectionView]) {

        int p = self.mainCollectionView.contentOffset.x/WIDTH;

        currentDex=p;


        for (int i=0; i<self.btnTitleArray.count; I++){

SKHomeBaseTitle *mode= self.btnTitleArray[i];

            if (i==p) {

                mode.orSelect=YES;

            }else{

                mode.orSelect=NO;

            }

}

[self.titleCollectionView reloadData];

        NSIndexPath *nextIndexPath = [NSIndexPath indexPathForItem:p inSection:0];

        [self.titleCollectionView scrollToItemAtIndexPath:nextIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];

        [self layoutSubview];

}

}

******当点击每个标题的时候******

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{

    if (collectionView==self.titleCollectionView) {

        [self changeMainCollectionViewContent:indexPath];

        currentDex=indexPath.row;

        for (int i=0; i<self.btnTitleArray.count;i++){

SKHomeBaseTitle *mode= self.btnTitleArray[i];

            if (i==indexPath.row) {

                mode.orSelect=YES;

            }else{

                mode.orSelect=NO;

            }

}

[self.titleCollectionView reloadData];

        [self layoutSubview];

    } else {


    }

}

最后就是在创建的每个视图控制器中根据往常的业务逻辑进行处理就行了,那么我们整个的封装就完成了,有不懂的小伙伴可以留言,或者加我的QQ号1849976000;我可以提供一下示例demo。

顺便把我所集效果给大家演示一下:


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容