iOS 动画(二)

2020-06-23  本文已影响0人  gaookey

iOS 动画(一)
iOS 动画(二)

CAEmitterCell

CAGradientLayer

CAGradientLayer 继承自 CALayer,它主要功能是能实现渐变的颜色。

let gradientLayer = CAGradientLayer();
gradientLayer.frame = view.bounds;
view.layer.addSublayer(gradientLayer)

gradientLayer.colors = [UIColor.cyan.cgColor, UIColor.orange.cgColor];
// 渐变颜色的区间分布,locations的数组长度和color一致,一般不用设置,默认是nil,会平均分布。
//gradientLayer.locations = [0.1, 0.2]
//映射locations中第一个位置,用单位向量表示,比如(0,0)表示从左上角开始变化。默认值是(0.5,0.0)。
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
//表示到右下角变化结束。默认值是(0.5,1.0)。
gradientLayer.endPoint = CGPoint(x: 1, y: 1)

CAGradientLayer 为粒子发射图层。该图层主要用于控制粒子展现范围、粒子发射位置、粒子发射形状、渲染模式等属性。

CAEmitterLayer

CAEmitterCell 粒子发射单元,用于对粒子系统中的单个粒子做更加精细的控制。比如控制粒子的移动速度、方向、范围。

粒子火焰效果

let emitterCell = CAEmitterCell()
emitterCell.name = "fire"// 粒子的名字
emitterCell.emissionLongitude = .pi
emitterCell.velocity = -1 // 粒子速度。负数表明向上燃烧,速度越大,火苗喷涌速度越快
emitterCell.velocityRange = 50 // 粒子速度范围
emitterCell.emissionRange = 1.1 // 周围发射角度
emitterCell.yAcceleration = -200 // 粒子 y 方向的加速度分量

emitterCell.scaleSpeed = 0.3 // 缩放比例 超大火苗
emitterCell.color = UIColor(red: 0.8, green: 0.4, blue: 0.2, alpha: 0.1).cgColor
//一般放一张图片,是我们粒子要展示的内容。图片要小,不然卡
emitterCell.contents = UIImage(named: "image")?.cgImage
// emitterCell.birthRate = 500  (火焰效果中每秒粒子的组成个数,个数越多,火焰越大越逼真。)
// 每个粒子存活时长
//emitterCell.lifetime = 5

let emitterLayer = CAEmitterLayer()
emitterLayer.position = view.center
//发射器的尺寸
emitterLayer.emitterSize = CGSize(width: 5, height: 5)
//渲染模式
emitterLayer.renderMode = .additive
//发射的模式
emitterLayer.emitterMode = .outline
//发射的形状,有6种值,分别是点、线、矩形、立方体、圆形、球形。
emitterLayer.emitterShape = .line
emitterLayer.emitterCells = [emitterCell]
view.layer.addSublayer(emitterLayer)

//粒子产生系数,默认为1,想关掉就设为0,这样就没有粒子产生了
emitterLayer.setValue(500, forKeyPath: "emitterCells.fire.birthRate") 
emitterLayer.setValue(1, forKeyPath: "emitterCells.fire.lifetime") 

霓虹效果

let emitterCell = CAEmitterCell()
emitterCell.emissionLongitude = .pi * 2
emitterCell.velocity = 50
emitterCell.velocityRange = 50
emitterCell.scaleSpeed = -0.2
emitterCell.scale = 0.1
emitterCell.greenSpeed = -0.1
emitterCell.redSpeed = -0.2
emitterCell.blueSpeed = 0.1
emitterCell.alphaSpeed = -0.2
//每秒粒子产生个数的乘数因子,会和layer的birthRate相乘, 然后确定每秒产生的粒子个数
emitterCell.birthRate = 100
emitterCell.lifetime = 4
emitterCell.color = UIColor.white.cgColor
emitterCell.contents = UIImage(named: "image")?.cgImage

let emitterLayer = CAEmitterLayer()
emitterLayer.position = view.center
emitterLayer.emitterSize = CGSize(width: 2, height: 2)

emitterLayer.renderMode = .backToFront
emitterLayer.emitterMode = .outline
emitterLayer.emitterShape = .circle
emitterLayer.emitterCells = [emitterCell]
view.layer.addSublayer(emitterLayer)

直播点赞粒子动画

let emitterLayer = CAEmitterLayer()
//发射器在xy平面的中心位置
emitterLayer.emitterPosition = CGPoint(x: UIScreen.main.bounds.width * 0.5, y: UIScreen.main.bounds.height - 200)
//发射器的尺寸大小
emitterLayer.emitterSize = CGSize(width: 30, height: 30)
//渲染模式
emitterLayer.renderMode = .unordered
//开启三维效果
emitterLayer.preservesDepth = true

var emitterCells = [CAEmitterCell]()
//创建粒子
for i in 1...9 {
    //发射单元
    let emitterCell = CAEmitterCell()
    //粒子的创建速率
    emitterCell.birthRate = 0.5
    //粒子存活时间
    emitterCell.lifetime = 10
    //粒子的生存时间容差
    emitterCell.lifetimeRange = 5
    //颜色
    //stepCell.color = UIColor(red: CGFloat(arc4random() % 256) / 255.0, green: CGFloat(arc4random() % 256) / 255.0, blue: CGFloat(arc4random() % 256) / 255.0, alpha: 1.0).cgColor
    //粒子显示的内容
    emitterCell.contents = UIImage(named: "image\(i)")?.cgImage
    //粒子的名字
    emitterCell.name = String(i)
    //粒子的运动速度
    emitterCell.velocity = 100
    //粒子的速度容差
    emitterCell.velocityRange = 50
    //旋转速度
    emitterCell.spin = CGFloat(Double.pi / 2)
    //透明度每过一秒就是减少0.1
    emitterCell.alphaSpeed = -0.1
    emitterCell.alphaRange = -0.1
    
    //粒子在xy平面的发射角度
    emitterCell.emissionLongitude = CGFloat(.pi + Double.pi / 2)
    //粒子发射角度容差
    emitterCell.emissionRange = CGFloat(Double.pi / 4)
    //缩放比例
    emitterCell.scale = 0.7
    emitterCell.scaleRange = 0.3
    emitterCells.append(emitterCell)
}
emitterLayer.emitterCells = emitterCells
view.layer.addSublayer(emitterLayer)

CAGradientLayer

光波扫描动画

let gradientLayer = CAGradientLayer()
gradientLayer.frame = CGRect(x: 100, y: 100, width: 200, height: 200)
//光波方向
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 0)
//设置光波颜色梯度
gradientLayer.locations = [0.0, 0.02, 0.02]
gradientLayer.colors = [UIColor.clear.cgColor, UIColor.black.cgColor, UIColor.clear.cgColor]
view.layer.addSublayer(gradientLayer)

let gradientAnimation = CABasicAnimation()
gradientAnimation.keyPath = "locations"
gradientAnimation.fromValue = [0.0, 0.02, 0.02]
gradientAnimation.toValue = [0.98, 0.98, 1.0]
gradientAnimation.duration = 3
gradientAnimation.repeatCount = 10
gradientLayer.add(gradientAnimation, forKey: nil)

实践:音响音量跳动动画

import UIKit

class ViewController: UIViewController {
    
    var gradientLayers = [CAGradientLayer]()
    var randomColors = [UIColor]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let audioBarNum: CGFloat = 15
        let audioBarW: CGFloat = (UIScreen.main.bounds.size.width - 10 * (audioBarNum + 1)) / audioBarNum
        
        for i in 0...15 {
            randomColors.append(UIColor(red: CGFloat(arc4random() % 256) / 255.0, green: CGFloat(arc4random() % 256) / 255.0, blue: CGFloat(arc4random() % 256) / 255.0, alpha: 1.0))
            
            let audioBar = UIView()
            audioBar.frame = CGRect(x: 10 + CGFloat(i) * (audioBarW + 10), y: 300, width: audioBarW, height: 100)
            audioBar.backgroundColor = randomColors[i]
            view.addSubview(audioBar)
            
            let gradientLayer = CAGradientLayer()
            gradientLayer.frame = audioBar.bounds
            gradientLayer.startPoint = CGPoint(x: 0, y: 0)
            gradientLayer.endPoint = CGPoint(x: 0, y: 1)
            audioBar.layer.addSublayer(gradientLayer)
            gradientLayers.append(gradientLayer)
        }
        
        Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(colorChange), userInfo: nil, repeats: true)
    }
    
    @objc func colorChange() {
        
        for layer in gradientLayers {
            let index = Int(arc4random_uniform(11))
            let color = randomColors[index]
            
            layer.colors = [UIColor.clear.cgColor, color.cgColor]
            layer.locations = [0, 1.0]
            
            let gradientAnimation = CABasicAnimation()
            gradientAnimation.keyPath = "locations"
            let beginValue = Float(arc4random_uniform(11)) / 10
            
            gradientAnimation.fromValue = [beginValue, beginValue]
            gradientAnimation.toValue = [1.0, 1.0]
            gradientAnimation.duration = 0.5
            layer.add(gradientAnimation, forKey: nil)
        }
    }
}
image.png

CAShapeLayer

UIBezierPath

override func draw(_ rect: CGRect) {
    
    //贝济埃曲线
    let bezierPath = UIBezierPath()
    //线条粗细
    bezierPath.lineWidth = 5
    //线条颜色
    UIColor.cyan.setStroke()
    //头尾形状
    bezierPath.lineCapStyle = .square
    //线条拐角
    bezierPath.lineJoinStyle = .round
    //绘制起始点
    bezierPath.move(to: CGPoint(x: 50, y: 200))
    bezierPath.addLine(to: CGPoint(x: 300, y: 300))
    bezierPath.addArc(withCenter: CGPoint(x: 200, y: 150), radius: 50, startAngle: 0, endAngle: .pi * 4 / 3, clockwise: true)
    
    //绘制闭合曲线
    bezierPath.close()
    //填充色
    UIColor.orange.setFill()
    //填充 填充色
    bezierPath.fill()
    
    bezierPath.stroke()
}

绘制动态图表

绘制折线动画

import UIKit

class FileView: UIView {
    
    private var chartLine = CAShapeLayer()
    private var pathAnimation = CABasicAnimation()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        backgroundColor = .white
        
        clipsToBounds = true
        chartLine.lineCap = .round
        chartLine.lineJoin = .round
        chartLine.fillColor = UIColor.white.cgColor
        chartLine.lineWidth = 10
        //属性为0,表明该动画效果开始绘制折线图时时一点点绘制,而非一次绘制完成
        chartLine.strokeEnd = 0
        
        layer.addSublayer(chartLine)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ rect: CGRect) {
        
        let line = UIBezierPath()
        line.lineWidth = 10
        line.lineCapStyle = .square
        line.lineJoinStyle = .round
        line.move(to: CGPoint(x: 50, y: 80))
        line.addLine(to: CGPoint(x: 150, y: 180))
        line.addLine(to: CGPoint(x: 180, y: 90))
        line.addLine(to: CGPoint(x: 300, y: 260))
        
        chartLine.path = line.cgPath
        chartLine.strokeColor = UIColor.cyan.cgColor
        
        pathAnimation.keyPath = "strokeEnd"
        pathAnimation.timingFunction = CAMediaTimingFunction(name: .linear)
        pathAnimation.fromValue = 0
        pathAnimation.toValue = 1
        pathAnimation.autoreverses = false
        pathAnimation.duration = 5
    }
    
    // 调用此方法开始划线动画
    func drawChartLine() {
        chartLine.strokeEnd = 1
        chartLine.add(pathAnimation, forKey: nil)
    }
}

绘制柱状图动画

import UIKit

class FileView: UIView {
    
    private var chartLine = CAShapeLayer()
    private var pathAnimation = CABasicAnimation()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        backgroundColor = .white
        
        clipsToBounds = true
        chartLine.lineCap = .round
        chartLine.lineJoin = .round
        chartLine.fillColor = UIColor.lightGray.cgColor
        chartLine.lineWidth = 30
        chartLine.strokeEnd = 0
        
        layer.addSublayer(chartLine)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ rect: CGRect) {
        
        let line = UIBezierPath()
        line.lineWidth = 30
        line.lineCapStyle = .square
        line.lineJoinStyle = .round
        
        for i in 0...5 {
            let x = CGFloat(60 + 70 * i)
            let y = CGFloat(100 + 20 * i)
            line.move(to: CGPoint(x: x, y: 215))
            line.addLine(to: CGPoint(x: x, y: y))
        }
        
        chartLine.path = line.cgPath
        chartLine.strokeColor = UIColor.cyan.cgColor
        
        pathAnimation.keyPath = "strokeEnd"
        pathAnimation.timingFunction = CAMediaTimingFunction(name: .linear)
        pathAnimation.fromValue = 0
        pathAnimation.toValue = 1
        pathAnimation.autoreverses = false
        pathAnimation.duration = 5
    }
    
    // 调用此方法开始划线动画
    func drawChartLine() {
        chartLine.strokeEnd = 1
        chartLine.add(pathAnimation, forKey: nil)
    }
}

调用 drawChartLine 方法绘制折线图动画和绘制柱状图动画开始执行动画

import UIKit

class ViewController: UIViewController {
    
    private lazy var fileView: FileView = {
        let view = FileView(frame: self.view.bounds)
        return view
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(fileView)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        fileView.drawChartLine()
    }
}

CAReplicatorLayer

主要用于图层的快速复制

旋转动画

import UIKit

class ViewController: UIViewController {
    
    var replicatorLayer = CAReplicatorLayer()
    
    private lazy var imageView: UIView = {
        let view = UIView(frame: CGRect(x: (UIScreen.main.bounds.size.width - 50 ) / 2 + 150, y: (UIScreen.main.bounds.size.height - 50) / 2, width: 50, height: 50))
        view.backgroundColor = .cyan
        return view
    }()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(imageView)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        let path = UIBezierPath()
        path.addArc(withCenter: view.center, radius: 150, startAngle: 0, endAngle: .pi * 2, clockwise: true)
        path.close()
        
        let animation = CAKeyframeAnimation(keyPath: "position")
        animation.path = path.cgPath
        animation.duration = 10
        animation.repeatCount = MAXFLOAT
        
        //设置100个layer图层
        replicatorLayer.instanceCount = 100
        //动画每0.2s复制一个layer图层
        replicatorLayer.instanceDelay = 0.2
        view.layer.addSublayer(replicatorLayer)
        imageView.layer.add(animation, forKey: nil)
    }
}

音量跳动动画

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let replicatorLayer = CAReplicatorLayer()
        replicatorLayer.frame = CGRect(x: 30, y: 50, width: 300, height: 200)
        //复制10份图层
        replicatorLayer.instanceCount = 10;
        //设置复制图层之间的渐变效果。设置图层沿x方向,每隔20个点复制一份。
        replicatorLayer.instanceTransform = CATransform3DMakeTranslation(20, 0, 0)
        //图层复制间隔0.2s
        replicatorLayer.instanceDelay = 0.2
        //剪切掉图层超出生效范围之外的部分
        replicatorLayer.masksToBounds = true
        replicatorLayer.backgroundColor = UIColor.black.cgColor
        
        let layer = CALayer()
        layer.frame = CGRect(x: 14, y: 200, width: 10, height: 100)
        layer.backgroundColor = UIColor.red.cgColor
        replicatorLayer.addSublayer(layer)
        view.layer.addSublayer(replicatorLayer)
        
        let animation = CABasicAnimation(keyPath: "position.y")
        animation.duration = 0.5
        //音量高度在200-180的范围内波动
        animation.fromValue = 200
        animation.toValue = 180
        animation.autoreverses = true
        animation.repeatCount = MAXFLOAT
        layer.add(animation, forKey: nil)
    }
}
image2.png

CATransform3D

CATransform3DMakeRotation

angle:动画的旋转角度

xyz:分别代表动画旋转时的旋转轴心

UIView.animate(withDuration: 5) {
    //修改锚点位置。锚点的默认值为 (0.5, 0.5),取值范围为 0~1 之间。
    self.imageView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    self.imageView.layer.transform = CATransform3DMakeRotation(.pi / 3, 1, 1, 0)
}

CATransform3D 矩阵

struct CATransform3D
{
    CGFloat m11(x缩放), m12(和m21一起决定z轴的旋转), m13(和m31一起决定y轴的旋转), m14;
    CGFloat m21(和m12一起决定z轴的旋转), m22(y轴方向进行缩放), m23, m24;
    CGFloat m31(和m13一起决定y轴的旋转), m32, m33(z轴方向进行缩放), m34(透视效果,m34 = -1 / D,D越小,透视效果越明显,必须在有旋转效果的前提下,才会看到透视效果。);
    CGFloat m41(x轴方向进行平移), m42(y轴方向进行平移), m43(z轴方向进行平移), m44;
}
UIView.animate(withDuration: 5) {
    var transform = CATransform3DIdentity
    transform.m34 = -1 / 20
    transform.m31 = 3
    transform.m13 = 3
    
    self.imageView.layer.transform = CATransform3DScale(transform, 1, 1, 1)
}

Cover Flow 效果代码实现

import UIKit

class ViewController: UIViewController {
    
    private lazy var imageView: UIImageView = {
        let image = UIImageView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
        image.image = UIImage(named: "0")
        image.layer.anchorPoint.y = 0
        return image
    }()
    
    private lazy var imageView2: UIImageView = {
        let image = UIImageView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
        image.image = UIImage(named: "0")
        image.layer.anchorPoint.y = 0
        return image
    }()
    
    private lazy var imageView3: UIImageView = {
        let image = UIImageView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
        image.image = UIImage(named: "0")
        image.layer.anchorPoint.y = 0
        return image
    }()
    
    private lazy var imageViews = [imageView, imageView2, imageView3]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(imageView)
        view.addSubview(imageView2)
        view.addSubview(imageView3)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        for i in 0..<imageViews.count {
            
            var imageTransform = CATransform3DIdentity
            imageTransform.m34 = -0.005
            imageTransform = CATransform3DTranslate(imageTransform, 0, 50, 0)
            imageTransform = CATransform3DScale(imageTransform, 0.95, 0.6, 1)
            
            if i == 0 {
                imageTransform = CATransform3DRotate(imageTransform, .pi / 4 / 2, 0, 1, 0)
            } else if i == 1 {
                imageTransform = CATransform3DRotate(imageTransform, -.pi / 4 / 2, 0, 1, 0)
            }
            
            let animation = CABasicAnimation(keyPath: "transform")
            animation.fromValue = NSValue(caTransform3D: imageViews[i].layer.transform)
            animation.toValue = NSValue(caTransform3D: imageTransform)
            animation.duration = 1
            
            let position = CABasicAnimation(keyPath: "position")
            if i == 0 {
                position.toValue = NSValue(cgPoint: CGPoint(x: 100, y: 10))
            } else if i == 1 {
                position.toValue = NSValue(cgPoint: CGPoint(x: 300, y: 10))
            } else {
                position.toValue = NSValue(cgPoint: CGPoint(x: 200, y: 20))
            }
            
            let group = CAAnimationGroup()
            group.duration = 1
            group.repeatCount = 1
            group.isRemovedOnCompletion = false
            group.fillMode = .forwards
            group.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
            group.animations = [animation, position]
            imageViews[i].layer.add(group, forKey: "\(i)")
        }
    }
}
image3.png

CATransition

let transition = CATransition()
transition.duration = 2
//设置动画类型
transition.type = .moveIn
//设置当前动画转场方向
transition.subtype = .fromTop
view.layer.add(transition, forKey: nil)

CATransitionType 动画类型

CATransitionSubtype 动画转场方向

视图过渡动画

视图控制器过渡动画实现

UIViewControllerAnimatedTransitioning

UINavigationControllerDelegate

TransitionAnimation.swift
import UIKit

class TransitionAnimation: NSObject, UIViewControllerAnimatedTransitioning {
    
    // MARK: - UIViewControllerAnimatedTransitioning
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        
        return 2
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        
        let fromVC = (transitionContext.viewController(forKey: .from))!
        let toVC = transitionContext.viewController(forKey: .to)!
        
        let fromVCRect = transitionContext.initialFrame(for: fromVC)
        let toVCRect = CGRect(x: 0, y: fromVCRect.size.height * 2, width: fromVCRect.size.width, height: fromVCRect.size.height)
        
        let fromView = fromVC.view!
        let toView = toVC.view!
        fromView.frame = fromVCRect
        toView.frame = toVCRect
        
        transitionContext.containerView.addSubview(fromView)
        transitionContext.containerView.addSubview(toView)
        
        UIView.animate(withDuration: 2, animations: {
            
            toView.frame = fromVCRect
            toView.alpha = 1
        }) { (finish) in
            transitionContext.completeTransition(true)
        }
    }
}
ViewController.swift
import UIKit

class ViewController: UIViewController, UINavigationControllerDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(red: CGFloat(arc4random() % 256) / 255.0, green: CGFloat(arc4random() % 256) / 255.0, blue: CGFloat(arc4random() % 256) / 255.0, alpha: 1.0)
        
        navigationController?.delegate = self
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        self.navigationController?.pushViewController(ViewController(), animated: true)
    }
    
    // MARK: - UINavigationControllerDelegate
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
        return TransitionAnimation()
    }
}

侧滑栏动画实现

import UIKit
import Accelerate

class SliderViewController: UIViewController {
    
    private lazy var blurView: UIView = {
        let view = UIView(frame: self.view.bounds)
        return view
    }()
    
    private lazy var contentView: UIView = {
        let view = UIView(frame: CGRect(x: -UIScreen.main.bounds.size.width * 0.5, y: 0, width: UIScreen.main.bounds.size.width * 0.5, height: UIScreen.main.bounds.size.height))
        view.backgroundColor = .cyan
        return view
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(blurView)
        view.addSubview(contentView)
    }
    
    func show() {
        
        var windowView = UIView()
        windowView = UIApplication.shared.windows.first!.rootViewController?.view! as! UIView
        blurView.layer.contents = blurImage(imageFromView(windowView)).cgImage
        view.alpha = 1
        UIView.animate(withDuration: 0.5, animations: {
            
            self.contentView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width * 0.5, height: UIScreen.main.bounds.size.height)
            self.contentView.alpha = 0.9
        })
    }
    
    func dismiss() {
        UIView.animate(withDuration: 0.5, animations: {
            
            self.contentView.frame = CGRect(x: -UIScreen.main.bounds.size.width * 0.5, y: 0, width: UIScreen.main.bounds.size.width * 0.5, height: UIScreen.main.bounds.size.height)
            self.contentView.alpha = 0.9
        }) { (finish) in
            self.view.alpha = 0
        }
    }
    
    // 蒙版模糊效果
    func blurImage(_ image: UIImage) -> UIImage {
        
        //设置图片模糊效果半径
        let blurRadix: UInt32 = 7
        let img = image.cgImage!
        let bitmapData = img.dataProvider?.data
        //import Accelerate
        var inputBuffer = vImage_Buffer()
        //获取图片的data数据内容、width、height、每行字节数
        inputBuffer.data = UnsafeMutableRawPointer(mutating: CFDataGetBytePtr(bitmapData))
        inputBuffer.width = vImagePixelCount(bitPattern: (img.width))
        inputBuffer.height = vImagePixelCount(bitPattern: (img.height))
        inputBuffer.rowBytes = img.bytesPerRow
        
        //构建一片空间大小和原始图片所占空间相同大小的数据空间
        let pixelBuffer = malloc(img.bytesPerRow * img.height)
        
        var outputBuffer = vImage_Buffer()
        outputBuffer.data = pixelBuffer
        outputBuffer.width = vImagePixelCount(bitPattern: (img.width))
        outputBuffer.height = vImagePixelCount(bitPattern: (img.height))
        outputBuffer.rowBytes = img.bytesPerRow
        
        //生成模糊效果的图片
        vImageBoxConvolve_ARGB8888(&inputBuffer, &outputBuffer, nil, 0, 0, blurRadix, blurRadix, nil, vImage_Flags(kvImageEdgeExtend))
        
        //构建RGB模糊空间
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let w = outputBuffer.width
        let h = outputBuffer.height
        let ctx = CGContext(data: outputBuffer.data, width: Int(w), height: Int(h), bitsPerComponent: 8, bytesPerRow: outputBuffer.rowBytes, space: colorSpace, bitmapInfo: (image.cgImage?.bitmapInfo.rawValue)!)
        
        let imageRef = ctx?.makeImage()
        let newImage = UIImage(cgImage: imageRef!)
        free(pixelBuffer)
        return newImage
    }
    
    // UIView 生成 UIImage
    func imageFromView(_ view: UIView) -> UIImage {
        
        UIGraphicsBeginImageContext(view.frame.size)
        let content = UIGraphicsGetCurrentContext()!
        view.layer.render(in: content)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return newImage
    }
}
上一篇 下一篇

猜你喜欢

热点阅读