import Foundation import UIKit import AsyncDisplayKit private let motionAmount: CGFloat = 32.0 public final class WallpaperBackgroundNode: ASDisplayNode { let contentNode: ASDisplayNode public var motionEnabled: Bool = false { didSet { if oldValue != self.motionEnabled { if self.motionEnabled { let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis) horizontal.minimumRelativeValue = motionAmount horizontal.maximumRelativeValue = -motionAmount let vertical = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis) vertical.minimumRelativeValue = motionAmount vertical.maximumRelativeValue = -motionAmount let group = UIMotionEffectGroup() group.motionEffects = [horizontal, vertical] self.contentNode.view.addMotionEffect(group) } else { for effect in self.contentNode.view.motionEffects { self.contentNode.view.removeMotionEffect(effect) } } self.updateScale() } } } public var image: UIImage? { didSet { self.contentNode.contents = self.image?.cgImage } } func updateScale() { if self.motionEnabled { let scale = (self.frame.width + motionAmount * 2.0) / self.frame.width self.contentNode.transform = CATransform3DMakeScale(scale, scale, 1.0) } else { self.contentNode.transform = CATransform3DIdentity } } public override init() { self.contentNode = ASDisplayNode() self.contentNode.contentMode = .scaleAspectFill super.init() self.clipsToBounds = true self.contentNode.frame = self.bounds self.addSubnode(self.contentNode) } override public func layout() { super.layout() self.contentNode.bounds = self.bounds self.contentNode.position = CGPoint(x: self.bounds.midX, y: self.bounds.midY) self.updateScale() } }