iOS 动画二十二: Simple 3D Animations

527 阅读1分钟

Simple 3D Animations 主要代码:

 func toggleSideMenu() {
    let isOpen = floor(centerViewController.view.frame.origin.x/menuWidth)
    let targetProgress: CGFloat = isOpen == 1.0 ? 0.0: 1.0
    
    UIView.animate(withDuration: animationTime,
      animations: {
        self.setMenu(toPercent: targetProgress)
      },
      completion: { _ in
        self.menuViewController.view.layer.shouldRasterize = false
      }
    )
  }
  
  func setMenu(toPercent percent: CGFloat) {
    centerViewController.view.frame.origin.x = menuWidth * CGFloat(percent)
    // menuViewController.view.frame.origin.x = menuWidth * CGFloat(percent) - menuWidth
    menuViewController.view.layer.transform = menuTransform(percent: percent)
    menuViewController.view.alpha = CGFloat(max(0.2, percent))
    
    let centerVC = centerViewController.viewControllers.first as? CenterViewController
    if let menuButton = centerVC?.menuButton {
        menuButton.imageView.layer.transform = buttonTransform(percent: percent)
    }
  }
  
  func buttonTransform(percent: CGFloat) -> CATransform3D {
        
    var identity = CATransform3DIdentity
    identity.m34 = -1.0/1000
    
    let angle = percent * .pi
    let rotationTransform = CATransform3DRotate(identity, angle, 1.0, 1.0, 0.0)
    
    return rotationTransform
  }
    
  func menuTransform(percent: CGFloat) -> CATransform3D {
        var identity = CATransform3DIdentity
        // To enable 3D transforms on a layer you need to set m34 to -1.0 / [camera distance]
        // 0.1...500: Very close, lots of perspective distortion.
        // 750...2,000: Nice perspective, content is clearly visible.
        // 2,000 and up: Almost no perspective distortion
        identity.m34 = -1.0/1000
        let remainingPercent = 1.0 - percent
        let angle = remainingPercent * .pi * -0.5
    
        let rotationTransform = CATransform3DRotate( identity, angle, 0.0, 1.0, 0.0)
    
        let translationTransform = CATransform3DMakeTranslation( menuWidth * percent, 0, 0)
        return CATransform3DConcat(rotationTransform, translationTransform)
  }
注 1:3d变换其实是一个矩阵变换:

矩阵

利用 CATransformLayer 做 3DLayer 效果。

利用 M34 做景深。

m34 用于按比例缩放 X 和 Y 的值来计算到底要离视角多远。 m34 的默认值是 0 ,我们可以通过设置 m34 为 -1.0 / d 来应用透视效果。

d 代表了想象中视角相机和屏幕之间的距离。一般 500-1000 效果挺好。

  1. 0.1...500: 非常接近,很多透视失真。
  2. 750...2,000: 不错的视角,内容清晰可见。
  3. 2,000 and up: 几乎没有透视扭曲。
注 2 : Moving the layerʼs anchor point

默认情况下,图层的 x 轴锚点坐标为 0.5,旋转的话会绕中心旋转。这里为了看起来更舒服,我们需要将锚点的 x 坐标设置为 1.0,以便菜单围绕其右边缘旋转,效果如下所示:

anchor point

最终效果图:

3D Animations

demo下载

参考:

  1. 3D变换
  2. INTRODUCTION TO 3D DRAWING IN CORE ANIMATION (PART 1)