函数式编程之动画组合

作者: Swifter丶 | 来源:发表于2017-03-22 21:57 被阅读282次

前言

本篇文章的提纲
1.举一个例子,理解函数式编程
2.用函数式编程的思想,做一个可以随意组合的动画库

什么是函数式编程?

关于函数式编程,网上有很多。浏览众多的文章后,对于函数式编程有了深刻的概念(其实就只记住了一句话): 函数是第一公民(函数可以当作参数,返回值。可以由多个低级的函数组合成一个高级的函数)。

下面我们来看一个例子

在图-1中,我们定义一个叫 AddGroup(加法组合) 的函数 。


图-1.png

很多人第一眼看到就觉得这就是一个闭包或者block嘛,还故意打码,搞出一副很深奥的样子。
虽然这是一个block,但是不能把它理解为block,因为当你认为这是block时,你就会想到回调。(反正我在网上看到这些例子的时候,就陷死在block的思维里了)。
这里我们把它理解为函数,或者公式,一套加法组合的公式。

在图-2中,我们定义生成一个加法组合公式的func ,我暂时把实现的细节马赛克了,因为我第一次看到这些例子的时候,陷死在了那些实现的细节里。

图-2

接下来就是开始使用这些函数

图-3

再用个高级一点的

图-4

上图-4中有一个叫compose的方法,作用是将add2和add3结合起来,组合成一个新的AddGroup。
第一个例子已经举完,下面就是源代码,大家可以直接复制粘贴到playground上去运行。在看下面源代码前可以先尝试着自己去实现。

//: Playground - noun: a place where people can play

import UIKit

typealias AddGroup = (Int)->Int //理解为的一系列加法组合的函数

func compose(_ addGroup1 : @escaping AddGroup , _ addGroup2 : @escaping AddGroup) -> AddGroup {
    return { a in
        return addGroup1(addGroup2(a))
    }
}

func add(_ num : Int) -> AddGroup {
    return { a in
        return a + num
    }
}

extension Int {
    //给Int扩展一个执行AddGroup这个函数的方法
    func excute(addGroup : AddGroup) -> Int {
        return addGroup(self)
    }
}

let add2 : AddGroup = add(2)//生成一个叫add2(加2)的AddGroup
let add3 : AddGroup = add(3)//生成一个叫add3(加3)的AddGroup
let addNew : AddGroup = compose(add2, add3)
let result = 1.excute(addGroup: addNew)//让1去执行这个AddGroup,得到结果为6
print("结果为 :",result)

开始做一个可以任意组合的动画库

先看一看这个库是如何调用的。

图-5

如上图-5所示。=> 这个符号表示,执行完前一个动画后再执行下一个动画。 + 加号符号表示 ,两个动画一起执行 。 + 的优先级高于 => , 先执行加号 ,在执行 =>。

看一看执行的效果

图-6

这算是动画比较多的了,但是调用起来还是比较简单,可读性也比较高的。

在来一个:

图-7
代码部分

首先我们定义一个要存储动画的类型

typealias AnimatState = (UIView) -> UIView

生成一个移动动画的方法,这里有个view.animCount , 我在后面会讲。

func move(to point: CGPoint , with duration : TimeInterval) -> AnimatState {
    return { view in

        view.animCount += 1
        
        UIView.animate(withDuration: duration, delay: 0, options: [] , animations: {
            view.frame.origin = point
        }, completion: { _ in
            view.frame.origin = point
            view.animCount -= 1
        })
    
        return view
    }
}

生成透明,旋转,缩放一系列的动画

透明
func fade(_ alpha: CGFloat , with duration : TimeInterval) -> AnimatState{
    return { view in
            
        view.animCount += 1
        
        UIView.animate(withDuration: duration, delay: 0, options: [] , animations: {
            view.alpha = alpha
        }, completion: { _ in
            view.alpha = alpha
            view.animCount -= 1
        })
        
        return view
    }
}
缩放
func scale(to scale: CGFloat , with duration : TimeInterval) -> AnimatState {
    return { view in
    
        view.animCount += 1
        
        UIView.animate(withDuration: duration, delay: 0, options: [] , animations: {
            view.transform = CGAffineTransform.init(scaleX: scale, y: scale)
        }, completion: { _ in
            view.transform = CGAffineTransform.init(scaleX: scale, y: scale)
            view.animCount -= 1
        })
        
        return view
    }
}
旋转
func rotate(by angle: CGFloat , with duration : TimeInterval ) -> AnimatState {
    return { view in
        
        view.animCount += 1
        UIView.animate(withDuration: duration, delay: 0, options: [] , animations: {
            view.transform = .init(rotationAngle: angle)
        }, completion: { _ in
            view.transform = .init(rotationAngle: angle)
            view.animCount -= 1
        })
        
        return view
    }
}

再生成一个空动画

func emptyAnim(_ duration : TimeInterval , closure : (()->Void)?) -> AnimatState{
    return { view in
    
        view.animCount += 1
        closure?()
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + duration, execute: { 
            view.animCount -= 1
        })
        return view
    }
}

一些最基本的动画就做完了。
接下来就开始做重载 + 操作符 , 加号表示的是将两个动画结合成一个能同时执行这两个小动画的大动画

func + (left : @escaping  AnimatState , right : @escaping AnimatState) -> AnimatState {
    return { view in
        return right(left(view))
    }
}

重载 => 操作符 ,=> 表示的是先执行左边的,然后再执行右边的。

func => (left : @escaping AnimatState , right :@escaping AnimatState) -> AnimatState {
    return { view in
        view.animCompleteHandles.append( { [weak view] in
            guard view != nil else { return }
            _ = right(view!)
        })
      return left(view)
    }
}

animCompleteHandles 是UView extension 的一个用来存放动画完成以后要做的动画回调的数组。 看一看它的实现

fileprivate var anim_comptele_handle_key : Void!
extension UIView {
  var animCompleteHandles : [AnimComleteHandle] {
        set{
            objc_setAssociatedObject(self, &anim_comptele_handle_key, ( newValue as Any ), .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
        get{
            return (objc_getAssociatedObject(self, &anim_comptele_handle_key) as? [AnimComleteHandle]) ?? [AnimComleteHandle]()
        }
    }
    
}

接下来,我们还需要一个东西来判断何时做完动画。这里我用的是模仿引用计数的方式, 就是前面提到的view.animCount,当执行一个动画的时候,计数 +1 , 执行执行完后计数 -1。当计数等于0时,我们要调用animCompleteHandles数组里面的最后一个元素进行回调,然后销毁。

extension UIView {
    fileprivate var animCount : Int {
        set{
            
            if newValue < 0 {
                objc_setAssociatedObject(self, &anim_count_key, 0, .OBJC_ASSOCIATION_COPY_NONATOMIC)
                return 
            }
            
            objc_setAssociatedObject(self, &anim_count_key, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
            
            if newValue == 0 {
                animCompleteHandles.popLast()?()
            }
            
        }
        get{
            return ( objc_getAssociatedObject(self, &anim_count_key) as? Int ) ?? 0
        }
    }
}
献上demo

https://github.com/Yuanjihua1/BuildingAnimation

相关文章

  • 函数式编程之动画组合

    前言 本篇文章的提纲1.举一个例子,理解函数式编程2.用函数式编程的思想,做一个可以随意组合的动画库 什么是函数式...

  • 函数式编程

    1 文章目标 为什么要学习函数式编程以及什么是函数式编程 函数式编程的特性(纯函数、柯里化、函数组合等) 函数式编...

  • 函数式编程之组合性

    设计可以组合的函数接口

  • Clojure 学习笔记 :11 函数组合

    Clojure 零基础 学习笔记 偏函数 串行宏 高阶函数 闭包 函数组合 --- 简单而又有力的武器 在函数式编...

  • Python 之路03 - Python基础3

    本节内容 函数与函数式编程 函数式编程之参数详解 局部变量与全局变量作用域嵌套函数 递归 函数式编程介绍 高阶函数...

  • js继承方式

    类式继承 构造函数继承 组合继承 类式继承 + 构造函数继承 原型式继承 寄生式继承 寄生组合式继承 寄生式继承 ...

  • Swift函数式编程之Map&Reduce&Fi

    Swift函数式编程之Map&Reduce&Filter 什么是函数式编程呢?函数式编程其实是一种编程思想, 代码...

  • 关于webpack loader的加载顺序

    函数组合 先介绍一个概念,函数组合:函数组合是函数式编程中非常重要的思想,它的实现的思路也没有特别复杂。 函数组合...

  • compose

    函数组合 先介绍一个概念,函数组合:函数组合是函数式编程中非常重要的思想,它的实现的思路也没有特别复杂。 函数组合...

  • 函数式编程

    什么是函数式编程? 函数式:functional 一种编程范式 函数式编程特点 把计算视为函数而非指令 纯函数式编...

网友评论

    本文标题:函数式编程之动画组合

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