• iOS菜单滚动联动内容区域功能实现


    平时开发APP中关于此功能还是比较经常碰到,本实例借用三个开源的插件,并对其中一个进行修改调整实现出想要的效果;本文重点介绍修改的内容跟三个插件的运用,这三个插件还可以各自扩展到其它项目的运用;

    效果图:

     

    本实例实现的效果:顶部的滚动菜单显示出所有的类型,每个类型都对应一种展示,可以在顶部的菜单进行滚动,内容区域也会跟着改变,或者是内容区域左右滑动,则顶部的滚动菜单也会跟着更改,顶部菜单的最右边有一个展示更多菜单的效果,用于弹出一个带箭头的窗;(源代码下载)

     带箭头的弹出视图插件 :https://github.com/xiekw2010/DXPopover

     内容区域滑动插件:https://github.com/nicklockwood/iCarousel

     及Codint.Net开源项目中的XTSegmentControl菜单滚动效果,此实例对它进行的修改

    1:插件及页面的初始化

    #import "ViewController.h"
    #import "oldChildVewController.h"
    #import "ChildViewController.h"
    #import "newChildVewController.h"
    #import "XTSegmentControl.h"
    #import "iCarousel.h"
    #import "Masonry.h"
    #import "menuCollectionViewCell.h"
    #import "DXPopover.h"
    
    #define kScreen_Height [UIScreen mainScreen].bounds.size.height
    #define kScreen_Width [UIScreen mainScreen].bounds.size.width
    #define kMySegmentControl_Height 44.0
    
    
    @interface ViewController ()<UICollectionViewDataSource, UICollectionViewDelegate,iCarouselDataSource, iCarouselDelegate>
    @property (strong, nonatomic) XTSegmentControl *mySegmentControl;
    @property (strong, nonatomic) NSArray *titlesArray;
    @property (strong, nonatomic) iCarousel *myCarousel;
    @property(assign,nonatomic)NSInteger curSelectIndex;
    @property (nonatomic, strong) DXPopover *popover;
    @property(assign,nonatomic)CGFloat popoverWidth;
    @property (strong, nonatomic) UICollectionView *myCollectionView;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.view.backgroundColor=[UIColor whiteColor];
        
        //初始化一个popover 用于弹窗效果的展示
        self.popover = [DXPopover new];
        _popoverWidth = kScreen_Width-20;
        
        __weak typeof(self) weakSelf = self;
        CGRect frame=self.view.bounds;
        
        //内容区滚动效果插件
        self.myCarousel = ({
            iCarousel *icarousel = [[iCarousel alloc] initWithFrame:frame];
            icarousel.dataSource = self;
            icarousel.delegate = self;
            icarousel.decelerationRate = 1.0;
            icarousel.scrollSpeed = 1.0;
            icarousel.type = iCarouselTypeLinear;
            icarousel.pagingEnabled = YES;
            icarousel.clipsToBounds = YES;
            icarousel.bounceDistance = 0.2;
            [self.view addSubview:icarousel];
            [icarousel mas_makeConstraints:^(MASConstraintMaker *make) {
                make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(64, 0, 0, 0));
            }];
            icarousel;
        });
        
        //添加滑块
        __weak typeof(_myCarousel) weakCarousel = _myCarousel;
        self.mySegmentControl = [[XTSegmentControl alloc] initWithFrame:CGRectMake(0, 20, kScreen_Width, 44) Items:self.titlesArray showRightButton:YES selectedBlock:^(NSInteger index) {
            weakSelf.curSelectIndex=index;
            weakCarousel.currentItemIndex=index;
            [weakSelf.myCollectionView reloadData];
        }];
        //当有右边键时 其响应的事件
        self.mySegmentControl.rightButtonBlock= ^(CGRect rightButtomRect)
        {
            //弹出插件的运用
            [weakSelf updateMyViewFrame];
            CGPoint startPoint =
            CGPointMake(CGRectGetMidX(rightButtomRect), CGRectGetMaxY(rightButtomRect) + 25);
            [weakSelf.popover showAtPoint:startPoint
                       popoverPostion:DXPopoverPositionDown
                      withContentView:weakSelf.myCollectionView
                               inView:weakSelf.view];
        };
        [self.view addSubview:self.mySegmentControl];
        
        //用于展示弹出效果里面的列表
        if (!_myCollectionView) {
            UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
            self.myCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0,50,kScreen_Width-40, 200) collectionViewLayout:layout];
            self.myCollectionView.backgroundColor=[UIColor whiteColor];
            self.myCollectionView.showsHorizontalScrollIndicator=NO;
            self.myCollectionView.showsVerticalScrollIndicator=NO;
            [self.myCollectionView registerClass:[menuCollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([menuCollectionViewCell class])];
            self.myCollectionView.dataSource = self;
            self.myCollectionView.delegate = self;
        }
    }

    其中XTSegmentControl为顶部菜单的创建,其中showRightButton是为了扩展是否显示右边更多菜单的事件,并把事件的响应Block到页面进行实现,此事例就是响应弹出窗的效果展现iCarousel为内容区域的滑动效果,DXPopover弹出窗的效果,UICollectionView则用于弹出窗里面的菜单列表

    //popver一些属性的设置
    -(void)updateMyViewFrame
    {
        CGRect tableViewFrame = self.myCollectionView.frame;
        tableViewFrame.size.width = _popoverWidth;
        self.myCollectionView.frame = tableViewFrame;
        self.popover.contentInset = UIEdgeInsetsZero;
        self.popover.backgroundColor = [UIColor whiteColor];
    }
    
    #pragma mark - Getter/Setter
    - (NSArray*)titlesArray
    {
        if (nil == _titlesArray) {
                _titlesArray = @[@"全部", @"互动", @"开源控件", @"文档", @"代码", @"高尔夫",@"主题",@"软件",@"股票"];
        }
        return _titlesArray;
    }

    2插件iCarouselDataSource, iCarouselDelegate代码实现

    #pragma mark iCarousel M
    - (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel{
        return [self.titlesArray count];
    }
    
    //滚动时内容视图的加载
    - (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view{
        [_mySegmentControl setScrollOffset:index];
        UIViewController *childContrll=[[ChildViewController alloc]init];
        UIView *my=childContrll.view;
        switch (index) {
            case 0:
            {
                my.backgroundColor=[UIColor blackColor];
                break;
            }
            case 1:
            {
                my.backgroundColor=[UIColor redColor];
                break;
            }
            default:
                childContrll=[[newChildVewController alloc]init];
                break;
        }
        return childContrll.view;
    }
    
    //滚动时 下划线的位置更新
    - (void)carouselDidScroll:(iCarousel *)carousel{
        if (_mySegmentControl) {
            [_mySegmentControl moveIndexWithProgress];
        }
    }
    
    //更新滚动其它两个控件的位置
    - (void)carouselCurrentItemIndexDidChange:(iCarousel *)carousel{
        self.curSelectIndex=carousel.currentItemIndex;
        [self.myCollectionView reloadData];
        if (_mySegmentControl) {
            _mySegmentControl.currentIndex = carousel.currentItemIndex;
        }
    }

    注意:内容区域的视图加载,及其滑动所响应的事件处理,原来的XTSegmentControl对于菜单字数不同时下划线会出现一些异常,本实例对它进行修改了;

    3:列表UICollectionViewDataSource, UICollectionViewDelegate功能的实现

    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
        return self.titlesArray.count;
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        menuCollectionViewCell *ccell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([menuCollectionViewCell class]) forIndexPath:indexPath];
        NSString *model=[self.titlesArray objectAtIndex:indexPath.row];
        ccell.curMenuModel=model;
        if (self.curSelectIndex==indexPath.row) {
            ccell.backgroundColor=[UIColor blueColor];
        }
        else
        {
            ccell.backgroundColor=[UIColor whiteColor];
        }
        return ccell;
    }
    
    
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
        return CGSizeMake((kScreen_Width-40)/3, 40);
    }
    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
        return UIEdgeInsetsZero;
    }
    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section{
        return 5;
    }
    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{
        return 5;
    }
    
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
        self.curSelectIndex=indexPath.row;
        //两个滚动的位置更新
        _myCarousel.currentItemIndex=self.curSelectIndex;
        [_mySegmentControl selectIndex:self.curSelectIndex];
        //隐藏弹出窗
        [self.popover dismiss];
    }

    注意:主要是在实现点击时滚动位置跟内容的区域要进行调整,并把弹出窗进行收缩的操作;

    4:XTSegmentControl下划线调整

    - (void)moveIndexWithProgress
    {
        CGRect origionRect = [_itemFrames[_currentIndex] CGRectValue];
        
        CGRect origionLineRect = CGRectMake(CGRectGetMinX(origionRect) + XTSegmentControlHspace, CGRectGetHeight(origionRect) - XTSegmentControlLineHeight, CGRectGetWidth(origionRect) - 2 * XTSegmentControlHspace, XTSegmentControlLineHeight);
        
        //增加下划线滚动的效果
        [UIView animateWithDuration:0.5 animations:^{
            _lineView.frame = origionLineRect;
        } completion:^(BOOL finished) {
            
        }];
        
    }

    5:扩展XTSegmentControl没有右边更多菜单的效果

        self.mySegmentControl = [[XTSegmentControl alloc] initWithFrame:CGRectMake(0, 20, kScreen_Width, 44) Items:self.titlesArray showRightButton:NO selectedBlock:^(NSInteger index) {
            weakSelf.curSelectIndex=index;
            weakCarousel.currentItemIndex=index;
            [weakSelf.myCollectionView reloadData];
        }];

    效果图:

    6:补充关于popover这个插件的如果有模态时,它会出现整个屏幕,如果不想要这种效果,可以自个设置一个背景视图效果,把popover模态效果关掉(self.popover.maskType=DXPopoverMaskTypeNone; //设置默认是否有模态);下面是写的一个实例:

     

    - (void)updateTableViewFrame {
        CGRect tableViewFrame = self.tableView.frame;
        tableViewFrame.size.width = _popoverWidth;
        self.tableView.frame = tableViewFrame;
        self.popover.contentInset = UIEdgeInsetsZero;
        self.popover.maskType=DXPopoverMaskTypeNone; //设置默认是否有模态
        self.popover.backgroundColor = [UIColor whiteColor];
    }
    
    - (void)showPopover {
        [self updateTableViewFrame];
    
        [self changeShowing];
        
        CGPoint startPoint =
            CGPointMake(CGRectGetMidX(self.btn.frame), CGRectGetMaxY(self.btn.frame) + 5);
        [self.popover showAtPoint:startPoint
                   popoverPostion:DXPopoverPositionDown
                  withContentView:self.tableView
                           inView:self.tabBarController.view];
    
        __weak typeof(self) weakSelf = self;
        self.popover.didDismissHandler = ^{
            [weakSelf bounceTargetView:weakSelf.btn];
        };
    }
    
    //自行增加一个背影层
    - (UIView *)myTapBackgroundView{
        if (!_myTapBackgroundView) {
            _myTapBackgroundView = ({
                UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 64, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height-64)];
                view.backgroundColor = [UIColor clearColor];
                UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(changeShowing)];
                [view addGestureRecognizer:tap];
                view;
            });
        }
        return _myTapBackgroundView;
    }
    
    - (void)changeShowing{
    
        if (self.isShowing) {//隐藏
            [UIView animateWithDuration:0.3 animations:^{
                self.myTapBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0];
            } completion:^(BOOL finished) {
                [self.popover dismiss];
                [self.myTapBackgroundView removeFromSuperview];
                self.isShowing = NO;
            }];
        }else{//显示
            [self.view addSubview:self.myTapBackgroundView];
            [UIView animateWithDuration:0.3 animations:^{
                self.myTapBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
            } completion:^(BOOL finished) {
                self.isShowing = YES;
            }];
        }
    }
  • 相关阅读:
    洛谷 P4001 [ICPC-Beijing 2006]狼抓兔子
    杂题20201201
    杂题20210103
    杂题20201010
    杂题20200928
    ACL1 Contest 1 简要题解
    杂题20200906
    杂题20200623
    USACO2020DEC Gold/Platinum 解题报告
    CSP-S2020游记
  • 原文地址:https://www.cnblogs.com/wujy/p/4885091.html
Copyright © 2020-2023  润新知