美文网首页iOS开发Swifty CodingiOS实战
一行代码搞定:下拉放大图片, 导航栏颜色渐变, 添加子控制器,

一行代码搞定:下拉放大图片, 导航栏颜色渐变, 添加子控制器,

作者: wuhao丶 | 来源:发表于2017-06-27 17:55 被阅读1377次

    本文要跟大家分享的是一个带有多种效果的控制器,仅需一行代码即可创建。
    这个控制器通过下拉可以放大顶部图片,上推可以使导航栏的颜色渐变,并且添加了三个子控制器,页面中间的三个按钮用来切换,当然,你也可以通过左右滑动来切换子控制器。
    代码的下载地址:WHAddVC
    接下来会分两点来说,一个是使用方法(超简单),第二个是核心代码的解读。
    先来看看gif效果。

    example.gif

    注意:使用了Masonry,请自行在项目中导入Masonry

    一、使用方法

    创建WHAddVC控制器的代码如下

    // 一行代码创建WHAddVC
    WHAddVC *addVC = [WHAddVC addVCWithTitle:@"TEST" topImage:[UIImage imageNamed:@"test"] chooseTitles:@[@"One",@"Two",@"Three"] chooseControllers:@[@"FirstViewController",@"SecondViewController",@"ThirdViewController"]];
    

    下面是更加详细的对于每个参数说明

    /**
     快速创建WHAddVC
    
     @param title 导航栏标题
     @param topImage 顶部图片
     @param chooseTitles 中间三个按钮的文字(字符串数组)
     @param chooseControllers 三个控制器名字(字符串数组)
     @return WHAddVC
     */
    + (WHAddVC *)addVCWithTitle:(NSString *)title topImage:(UIImage *)topImage chooseTitles:(NSArray *)chooseTitles chooseControllers:(NSArray *)chooseControllers;
    

    其中数组chooseControllers需要是已经创建好了的三个控制器的名字,字符串形式,方法里会根据传入的字符串自动转换为类,自动初始化控制器并加入到下方可滑动切换的界面里。
    WHAddVC还带有一个BOOL类型的属性可供设置。

    /** 顶部图片模糊效果,YES模糊,NO不模糊,默认不模糊 */
    @property (nonatomic, assign) BOOL blur;
    

    你可以这样操作:

    // 一行代码创建WHAddVC
    WHAddVC *addVC = [WHAddVC addVCWithTitle:@"TEST" topImage:[UIImage imageNamed:@"test"] chooseTitles:@[@"One",@"Two",@"Three"] chooseControllers:@[@"FirstViewController",@"SecondViewController",@"ThirdViewController"]];
    
    // 设置blur属性,给顶部图片添加模糊效果
     addVC.blur = YES;
    

    二、核心代码

    1. 下拉放大图片

    可以结合下面的代码和注释。
    要做到下拉放大图片,我的思路是修改图片的高度约束。利用pan拖拽手势拿到滑动的点,从而拿到滑动时图片底部距离控制器顶部的距离delta,把图片高度约束更新为delta,如果delta大于图片高度,在更新约束的时候图片会跟着放大。
    当停止拖拽,判断一下delta的高度,如果依然大于初始高度,则再次更新约束把图片复位。这就是放大的图片在放手的时候会自动恢复的原因。

    // 添加手势,可以做到上滑下滑
    - (void)addPanGesture {
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
        [self.view addGestureRecognizer:pan];
    }
    
    // 手势方法
    - (void)pan:(UIPanGestureRecognizer *)pan {
        // 拿到滑动点
        CGPoint movePoint = [pan translationInView:pan.view];
        [pan setTranslation:CGPointZero inView:pan.view];
        
        // 更新图片的高度
        [_imageView mas_updateConstraints:^(MASConstraintMaker *make) {
            // 得到图片底部距离控制器顶部的距离
            CGFloat delta = _imageView.frame.size.height + movePoint.y;
            // 为了不遮挡导航栏,delta>=64
            if (delta <= 64) {
                delta = 64;
            }
            // 上推缩短图片,下拉放大图片
            make.height.mas_equalTo(delta);
        }];
        
        CGFloat maxValue = 200;
        CGFloat minValue = 64;
        CGFloat ratio = (_imageView.frame.size.height - 64) / (maxValue - minValue);
    
        // 根据滑动距离得到的比例来控制导航栏的颜色和透明度
        if (_imageView.frame.size.height<200) {
            self.naviBarAlpha =  1 - ratio;
            self.barRenderValue = ratio;
        }
    
        // 停止pan手势的时候
        if (pan.state == UIGestureRecognizerStateEnded) {
            [_imageView mas_updateConstraints:^(MASConstraintMaker *make) {
                CGFloat delta = _imageView.frame.size.height + movePoint.y;
                if (delta<=200) {
                    make.height.mas_equalTo(delta);
                }else {
                    // 停止pan手势时,如果高度大于图片高度200,则让图片恢复原始状态
                    make.height.mas_equalTo(200);
                    // 初始状态,导航栏标题透明
                    [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor colorWithWhite:_barRenderValue alpha:0]}];
                    self.naviBarAlpha =  0;
                }
            }];
        }
    }
    

    2. 导航栏颜色渐变

    结合下面的代码和注释来解读。
    首先,导航栏背景和标题文字初始化都为透明。请查看WHAddVC代码里的setInit方法。接着利用drawRect方法自定义一个导航栏视图(WHNavView)来充当导航栏。
    设计两个属性naviBarAlpha和barRenderValue,用来控制颜色和透明度。然后就根据pan手势拖拽的距离,计算出一个比例ratio,在ratio动态改变的时候,根据ratio来改变naviBarAlpha和barRenderValue的值,最后,利用setNaviBarAlpha和setBarRenderValue方法使导航栏颜色渐变。

    // 控制颜色和透明度变化的核心代码
    {
        CGFloat maxValue = 200;
        CGFloat minValue = 64;
        // 图片高度的改变,计算出一个变化的ratio
        CGFloat ratio = (_imageView.frame.size.height - 64) / (maxValue - minValue);
        // 根据ratio改变naviBarAlpha和barRenderValue的值
        if (_imageView.frame.size.height<200) {
            self.naviBarAlpha =  1 - ratio;
            self.barRenderValue = ratio;
        }
    }
    
    // 设置导航栏透明度
    - (void)setNaviBarAlpha:(CGFloat)naviBarAlpha {
        _naviBarAlpha = naviBarAlpha;
        self.navView.alpha = naviBarAlpha;
    }
    
    // 设置导航栏文字颜色
    - (void)setBarRenderValue:(CGFloat)barRenderValue {
        _barRenderValue = barRenderValue;
        [self.navigationController.navigationBar setTintColor:[UIColor colorWithWhite:barRenderValue alpha:1]];
        [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor colorWithWhite:barRenderValue alpha:1]}];
    }
    

    3. 添加子控制器

    如下图,WHAddVC下面的三个按钮里并不是三张图片,而是三个子控制器,每个控制器都是单独出来的UIViewController。代码在图片后面。


    子控制器.png
    // 添加三个子控制器
    {
        // 由于传进来的是三个控制器的名字(字符串),这里根据字符串转成Class
        Class First = NSClassFromString(_chooseControllers[0]);
        Class Second = NSClassFromString(_chooseControllers[1]);
        Class Third = NSClassFromString(_chooseControllers[2]);
        
        FirstViewController *firstVC = [[First alloc] init];
        SecondViewController *secondVC = [[Second alloc] init];
        ThirdViewController *thirdVC = [[Third alloc] init];
        
        [self addChildViewController:firstVC];
        [self addChildViewController:secondVC];
        [self addChildViewController:thirdVC];
        
        [_containerView addSubview:firstVC.view];
        [_containerView addSubview:secondVC.view];
        [_containerView addSubview:thirdVC.view];
        
        [firstVC didMoveToParentViewController:self];
        [secondVC didMoveToParentViewController:self];
        [thirdVC didMoveToParentViewController:self];
    }
    

    4. 左右滑动的同时切换按钮

    之所以能够通过左右滑动来切换控制器,是用了一个UIScrollView,在ScrollView中添加一个View来撑开scrollView,这个View的宽度刚好是三个scrollView的宽度。
    重点在这里:在scrollViewDidScroll方法中,把ScrollView滑动的x轴距离的三分之一传给chooseView。然后在WHChooseView.m的setOffsetX方法里改变按钮的选中状态。
    根据偏移的距离来更新按钮下方线条的约束,并且改变按钮的选中状态。
    集体操作可以下载代码WHAddVC

    /************************WHAddVC.m************************************/
    
    /**
     * tracking:触摸scrollView , 还没进行拖拽
     * dragging:拖拽scrollView
     * decelerating:没有拖拽scrollView , 但是正在减速(移动)
     */
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        if (scrollView.isTracking || scrollView.isDragging || scrollView.isDecelerating) {
            // 把ScrollView滑动的x轴距离的三分之一传给chooseView
            CGFloat offsetX = scrollView.contentOffset.x / 3;
            _chooseView.offsetX = offsetX;
        }
    }
    
    
    /************************WHChooseView.m************************************/
    
    // WHChooseView的setOffsetX方法里改变按钮的选中状态
    - (void)setOffsetX:(CGFloat)offsetX {
        _offsetX = offsetX;
        // 改变按钮下面的线条的约束
        [_singleLine mas_updateConstraints:^(MASConstraintMaker *make) {
            make.centerX.equalTo(_firstButton).offset(offsetX);
        }];
        NSInteger index = offsetX / _firstButton.frame.size.width + 0.5;
        _preButton.selected = NO;
        // 改变按钮选中状态
        self.buttonArray[index].selected = YES;
        _preButton = self.buttonArray[index];
    }
    

    后记

    1. WHAddVC下载之后,把WHAddVC文件夹拖入工程即可直接使用。
    2. 注意!需要用到Masonry,请自行把Masonry导入工程
    3. 推荐简单又好用的分类集合:WHKit

    github地址:https://github.com/remember17

    相关文章

      网友评论

      • 天真烂漫的孩子:如果下面的三个控制器是三个tableView 上下滑动,这效果不一样的
      • zl520k:要判断手势的方向,不然下拉和左右不自然的
        wuhao丶:谢谢,晚点我看一下:smiley:

      本文标题:一行代码搞定:下拉放大图片, 导航栏颜色渐变, 添加子控制器,

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