zoukankan      html  css  js  c++  java
  • 如何使用autolayout的UIView加入动画

           


    hi,all:

    在经过了一番犹豫之后,我决定将我自己做的这个小APP的源代码发布给大家:

    其出发点是和大家一起学习iOS开发,仅供学习參考之用。

    之前代码是托管与gitlab

    上的。今天我将其pull到github上来了,大家能够自行下载:git clone git@github.com:lihux/twentyThousandTomatoes.git没有安装git或者不会用的童鞋。

    请猛戳github地址:https://github.com/lihux/twentyThousandTomatoes,进去之后选

    择download zip下载就可以。

     

    当我们对一个UIView使用了autolayout自己主动布局之后。也就意味着我们放弃了

    传统的通过设置view的frame等方式手动的改动、确定这个view的位置、尺寸属性

    甚至从某种程度上讲,我们应该忘记view的frame属性:它的确定不再取决于我

    (手动的直接修改),而是通过我们在storyboard或者code中提供的约束条件

    (constraints),通过一个自己主动布局引擎(苹果为autolayout採用的是Cassowary

    布局引擎,參考文档:点击打开链接),算出这个view的frame。因此我们能够

    觉得使用了autolayout的view的frame属性是一个仅仅的属性。

    在代码里觉得的修改

    这个view的frame并不能对这个view的frame产生真正的效果(事实也确实如此)。

          如今问题就来了,在曾经我们常常通过对一个view的frame的改动产生view移动

    的动画效果,那么在使用了autolayout的view世界中我们该怎样实现同样的效果呢?

    答案是。我们“将计就计”,通过改变这个view上的某个约束constraint然后在uiview的

    animation block中触发layout来实现。

    一、预期效果

            以下我们以一个简单的样例来进行具体的说明:

            如上图所看到的。整个界面都使用了autolayout,如今我们想实现这样一个效果:

    我们点击显示生日的button的时候,整个view向上滑动,同一时候向上推出一个日期

    选取器(date picker)。类似于点击textfield。弹出键盘后整个界面为了避免被遮

    住而向上移动的效果。

    选取完毕日期后点击生日日期button或者完毕button整个view向

    下缩回,同一时候date picker向下滑出可视范围。

    二、实现细节

            首先来看一眼storyboard中view的层级结构:例如以下图所看到的,从图中我们能够

    看到。整个view的布局相当简单。就两级:根view和我们的date picker view,其

    中date picker view包括了一个完毕button和系统的date picker。这种话。要实现

    整个view和date picker view同一时候上移的效果,我们仅仅须要对根view和date picker

     view同一时候做动画就可以。


            考虑怎样实现根view的动画效果,这里我们能够巧妙的通过改动根view的

    bounds属性来实现根view的上移效果。注意这里我们须要明确view的bounds属性

    和frame属性的差别,前者是相对于当前view的本地坐标系而言的。而后者则是相

    对于当前view的父view的坐标系而言的。

            简单的讲,frame决定了一个view相对于父view的position和size信息。而

    bounds则决定了当前view展示的内容相对于本地坐标系的位置。

    这里我们将view

    身的可视内容和subviews能够看做一页纸上的内容信息,而view本身可以看成

    是一枚放于纸上的放大镜,放大镜的大小不一定是和纸(content size)同样大小

    的。bounds属性的作用就是确定这枚放大镜相对于纸的位置:一个bounds =

    (0, 200, 300, 300)就意味着我们要将这枚放大镜向纸的下方移动200个points,但

    放大镜相对于父view的位置仍是保持不变的,这样给我们的效就是这个view(显

    示的内容)向上移动了200个points.


            修改bounds的origin属性并不会修改这个view的frame,通过这样的展示内容的

    移动给我们产生一种view向上移动了的幻觉。如上图中。“哪个位置...”为成为我们

    放大镜中看到的第一行。

            根view上移动画的效果攻克了,以下我们再来看日期选取器date picker。在

    storyboard中对其添加的约束例如以下:定高207、trailing/leading/top相对于super 

    view (根view)的位置。


            确定date picker view y轴方向上下移动的约束显然是top约束。点开top约束,

    能够看到该约束的具体内容:

            一个约束能够描写叙述为:firstItem.attributeA = secondItem.attributeB * multipler 

    constant。

    结合上图我们能够得出date picker view的top约束为

    datePickerView.Top = topLayoutGuide.bottom * 1 + 400

    我们能够通过改动这里的constant值来改动这个top约束以达到预期效果,事实

    上通过改动而不是删除旧的constraint再加入新的constraint也正是苹果所推荐的,

    NSLayoutConstraint.h头文件里有例如以下说明:


            这样。date picker view的上下移动就能够通过获取并改动其top约束来实现。

    须要注意的是在代码中获取datepicker view的top约束实际上是要在其父view的

    constraints数组中查找。这是由于每一个view的constraints数组中保存的实际上是

    layout 子view所需的约束的集合。

    我们还要定义个辅助BOOL变量,已推断date picker view是否以弹出:

    <span style="font-size:18px;">@property (nonatomic, assign) BOOL hasShowPickerView;</span>

           接下来定义一个辅助函数,用于查找date picker view的top约束并改动其

    constant属性为给定的值:

    - (void)replacePickerContainerViewTopConstraintWithConstant:(CGFloat)constant
    {
        for (NSLayoutConstraint *constraint in self.pickerContainerView.superview.constraints) {
            if (constraint.firstItem == self.pickerContainerView && constraint.firstAttribute == NSLayoutAttributeTop) {
                constraint.constant = constant;
            }
        }
    }
    


            代码里我们在picker container view (即文中的date picker view)的

    superview的constraints属性中查找,假设发现firstItem和firstAttribute属性各自是

    date picker view和top,则该constraint即为目标约束,然后改动其constant属性。

    在view首次被载入的时候我们想确保date picker view 处于整个view的最底部即隐

    藏的状态,因而我们在viewcontroller的viewDidLoad方法中调用辅助方法改动一下

    date picker view的top约束:

    <span style="font-size:18px;">[self replacePickerContainerViewTopConstraintWithConstant:self.view.frame.size.height];</span>

            在首次点击birthday button的时候动画改动根view的bounds和date picker 

    view的top constraint。注意上移gap的计算。

    再次点击birthday button的时候将根

    view的bounds恢复到正常值,date picker view的top constraint也恢复到viewDidLoad

    中设置的值:

    <span style="font-size:18px;">- (IBAction)didTapOnBirthdayButton:(id)sender
    {
        self.hasShowPickerView = !self.hasShowPickerView;
        if (self.hasShowPickerView) {
            CGRect birthdayButtonFrame = self.birthdayButton.frame;
            birthdayButtonFrame = [self.view convertRect:birthdayButtonFrame fromView:self.birthdayButton.superview];
            CGFloat birthdayButtonYOffset = birthdayButtonFrame.origin.y + birthdayButtonFrame.size.height;
            CGFloat gap = birthdayButtonYOffset - (self.view.frame.size.height - self.pickerContainerView.frame.size.height);
            CGRect bounds = self.view.bounds;
            if (gap > 0) {
                bounds.origin.y = gap;
            } else {
                gap = 0;
            }
            [self replacePickerContainerViewTopConstraintWithConstant:birthdayButtonYOffset];
            [UIView animateWithDuration:0.25 animations:^{
                self.view.bounds = bounds;
                [self.view layoutIfNeeded];
            }];
        } else {
            [self replacePickerContainerViewTopConstraintWithConstant:self.view.frame.size.height];
            CGRect bounds = self.view.bounds;
            bounds.origin.y = 0;
            [UIView animateWithDuration:0.25 animations:^{
                self.view.bounds = bounds;
                [self.view layoutIfNeeded];
            }];
        }
    }
    </span>


            上述代码中的[self.view layoutIfNeed]去掉也是没问题的。可能比較费解的是

    根view.bounds.origin.y的上移gap的计算以及top constraint的constant值的计算。

    关键实在真正理解view的frame和bounds的意义。

            至此程序达到了预期的效果。以下的gif图展示了动画效果。

    1.竖屏:



    2.横屏:


    三、小结

            在使用autolayout之前我们敲代码控制界面的构成就好比是开一辆手动挡的汽

    车,尽管频繁换挡(改动frame)非常繁琐。却也非常享受那种能够全然控制汽车档位的

    自由感。使用了autolayout之后则一下子升级为了自己主动挡汽车,切换档位的活不再由

    我们直接操作。而仅仅能通过油门(constraints)的大小来间接的改变汽车的档位。

    自己主动挡汽车里,我们必需要放弃直接控制档位的想法。那是不可能的了,我们必需要

    学会通过熟练掌握脚下的油门和刹车来控制车速。在习惯了自己主动挡之后。相信大家也

    一样可以得心应手的做自己想做的事情。


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    MFC记录
    【转】linux下tty,控制台,虚拟终端,串口,console(控制台终端)详解----不错
    【转】五大绝招复制不能复制的网页文字
    【转】DELL戴尔N4050笔记本拆机(图文)
    【转】Linux下tar.xz结尾的文件的解压方法
    【转】在Ubuntu 12.04 上为Virtualbox 启用USB 设备支持--不错
    【转】Android adb shell操作时出现“ XXX ... Read-only file system”解决办法--不错
    【转】VirtualBox direct access to SD Card in Windows--不错
    网址
    TensorFlow 学习(九)—— 初始化函数(概率分布函数 api、常数生成函数)
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4906187.html
Copyright © 2011-2022 走看看