写点什么

Swift 仿自如 App 裸眼 3D 效果

用户头像
关注
发布于: 2 小时前
Swift 仿自如 App 裸眼 3D 效果

前两天看了自如客APP裸眼3D效果的实现,感觉实现的 banner 设计的很有创意,效果很是惊艳。又看到拿去吧你!Flutter 仿自如 App 裸眼 3D 效果,然后决定使用 Swift 实现一下。


最后实现的项目为 Banner3D,可以点击查看运行效果。


原理

平时的 banner 都是使用的一张图片,为了达到 3D 的效果,需要将一张图片分成三张,也就是将原来的一张 banner 图片分成三个图层,再将图层分别导出为相同大小的图片。将这三张图片叠加在一起,从后往前分为背景、中景和前景。



当手机的旋转时,中景始终保持不变,给背景和中景位置添加相反的偏移量,就可以达到 3D 的效果了。



原理很简单,接下里就是背景和前景根据什么进行偏移?加速计?还是磁场?陀螺仪?还是重力?


我们先来看各个名词的定义:


  • 加速度为设备在三维空间的瞬时加速度;

  • 磁场为设备相对于地球磁场的方向;

  • 陀螺仪(Gyro)为设备在三个主轴上的瞬时旋转;

  • 重力(Gravity)为重力在设备各个方向上的分量。重力始终指向地球,通过设备三个方向上的不同分量来表示重力的方向,分量的范围为 0 到 1。



明白这几个定义之后,很明显我们应该选择 重力 的变化来修改图片的位移。再具体点就是,通过重力在设备 x 轴上的变化来修改图片左右的位移距离,通过重力在设备 y 轴上的变化来修改图片上下的位移距离。

实现

CMMotionManager 负责获取和处理手机的运动信息,是 Core Motion 库的核心类,可以使用 CMMotionManager 来获取重力信息,


import CoreMotion
lazy var motionManager: CMMotionManager = { let manager = CMMotionManager() manager.deviceMotionUpdateInterval = deviceMotionUpdateInterval return manager}()
复制代码


使用 motionManager 时,有几点需要注意:


  1. 获取设备信息时,有 pull 和 push 两种方式,苹果更推荐使用 pull;

  2. motionManager 尽可能使用单利来管理,不要创建多个实例。


这里就不详细介绍了,可以看 iOS传感器与CMMotionManager


开启获取设备信息更新回调,获取重力方向。


private func startMotion() {    // 检查是否可用    guard motionManager.isDeviceMotionAvailable else {        return    }        motionManager.startDeviceMotionUpdates(to: OperationQueue.main) { [weak self] deviceMotion, error in            guard let motion = deviceMotion else {            return        }        // motion.gravity 为重力方向        self?.update(gravityX: motion.gravity.x,                        gravityY: motion.gravity.y,                        gravityZ: motion.gravity.z)
}}
复制代码


根据重力方向给前景和背景添加位移动画。


func update(gravityX: Double, gravityY: Double, gravityZ: Double) {            let timeInterval = sqrt(pow((gravityX - lastGravityX), 2) + pow((gravityY - lastGravityY), 2)) * deviceMotionUpdateInterval
let animationKey = "positionAnimation" let newBackImageViewCenter = self.center.with { $0.x += CGFloat(gravityX) * maxOffset $0.y += CGFloat(gravityY) * maxOffset } let backImageViewAnimation = CABasicAnimation(keyPath: "position").then { $0.fromValue = NSValue(cgPoint: self.backImageViewCenter) $0.toValue = NSValue(cgPoint: newBackImageViewCenter) $0.duration = timeInterval $0.fillMode = .forwards $0.isRemovedOnCompletion = false } backImageView.layer.do { $0.removeAnimation(forKey: animationKey) $0.add(backImageViewAnimation, forKey: animationKey) } let newFrontImageViewCenter = self.center.with { $0.x -= CGFloat(gravityX) * maxOffset $0.y -= CGFloat(gravityY) * maxOffset } let frontImageViewAnimation = CABasicAnimation(keyPath: "position").then { $0.fromValue = NSValue(cgPoint: self.frontImageViewCenter) $0.toValue = NSValue(cgPoint: newFrontImageViewCenter) $0.duration = timeInterval $0.fillMode = .forwards $0.isRemovedOnCompletion = false } frontImageView.layer.do { $0.removeAnimation(forKey: animationKey) $0.add(frontImageViewAnimation, forKey: animationKey) } self.backImageViewCenter = newBackImageViewCenter self.frontImageViewCenter = newFrontImageViewCenter}
复制代码


到此就可以实现 3D 的效果了。


最后可以查看完成的代码Banner3D

参考资料

  1. 使用到了拿去吧你!Flutter 仿自如 App 裸眼 3D 效果中的图片

用户头像

关注

还未添加个人签名 2017.10.17 加入

还未添加个人简介

评论

发布
暂无评论
Swift 仿自如 App 裸眼 3D 效果