SwiftSwiftUICore Animation
Last updated at 2023-09-09

Custom CALayer Preview in SwiftUI

ClickUp
Note
AI Status
Last Edit By
Last edited time
Sep 9, 2023 08:24 AM
Metatag
Slug
custom-calayer-preview-swiftui
Writer
Published
Published
Date
Sep 9, 2023
Category
Swift
SwiftUI
Core Animation
By overriding layerClass you can tell UIKit what CALayer class to use for a UIView's backing layer.
That way you can reduce the amount of layers, and don't have to do any manual layout.

Full Code with Explanation Below

import SwiftUI struct LayerPreviewer: View { var body: some View { LayerDrawer<CAGradientLayer> { layer in layer.colors = [ UIColor.red.cgColor, UIColor.blue.cgColor ] } } } struct LayerPreviewer_Previews: PreviewProvider { static var previews: some View { LayerPreviewer() } } struct LayerDrawer<Layer: CALayer>: UIViewRepresentable { let callback: (Layer) -> Void init(_ callback: @escaping (Layer) -> Void) { self.callback = callback } func makeUIView(context: Context) -> DrawerView<Layer> { let view = DrawerView<Layer>(frame: .zero) view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) view.setContentHuggingPriority(.defaultLow, for: .vertical) return view } func updateUIView(_ uiView: DrawerView<Layer>, context: Context) { callback(uiView.layer as! Layer) } } final class DrawerView<Layer: CALayer>: UIView { override class var layerClass: AnyClass { Layer.self } var actualLayer: Layer { layer as! Layer } }

Explain Please

This SwiftUI code defines a custom LayerPreviewer view that allows you to create and preview a Core Animation (CALayer) within a SwiftUI view hierarchy.
It uses the LayerDrawer and DrawerView components to achieve this.
  1. LayerPreviewer is a SwiftUI View that you can use to preview a CALayer. It uses the LayerDrawer view to configure and draw the layer.
    1. struct LayerPreviewer: View { var body: some View { LayerDrawer<CAGradientLayer> { layer in layer.colors = [ UIColor.red.cgColor, UIColor.blue.cgColor ] } } }
  1. In the body of LayerPreviewer, it uses LayerDrawer<CAGradientLayer> to create a CAGradientLayer. Inside the LayerDrawer initializer, you pass a closure that configures the properties of the CAGradientLayer, setting its colors property to a gradient from red to blue.
    1. LayerDrawer<CAGradientLayer> { layer in layer.colors = [ UIColor.red.cgColor, UIColor.blue.cgColor ] }
  1. LayerDrawer is a SwiftUI UIViewRepresentable view that bridges between SwiftUI and UIKit. It's generic over a Layer type that should be a subclass of CALayer. It takes a callback closure that allows you to configure the layer.
    1. struct LayerDrawer<Layer: CALayer>: UIViewRepresentable { let callback: (Layer) -> Void init(_ callback: @escaping (Layer) -> Void) { self.callback = callback } func makeUIView(context: Context) -> DrawerView<Layer> { let view = DrawerView<Layer>(frame: .zero) view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) view.setContentHuggingPriority(.defaultLow, for: .vertical) return view } func updateUIView(_ uiView: DrawerView<Layer>, context: Context) { callback(uiView.layer as! Layer) } }
  1. In makeUIView(context:), it creates an instance of DrawerView<Layer>, a UIKit UIView subclass that acts as a container for your custom layer. It sets the compression resistance and content hugging priorities for this view.
  1. In updateUIView(_:context:), it calls the callback closure with the actual layer (uiView.layer as! Layer) to configure it based on your specifications.
  1. DrawerView is a UIKit UIView subclass that provides a layer-based view. It overrides the layerClass property to specify the type of layer it should use, which is defined by the generic Layer type.
    1. final class DrawerView<Layer: CALayer>: UIView { override class var layerClass: AnyClass { Layer.self } var actualLayer: Layer { layer as! Layer } }
  1. Finally, there's a LayerPreviewer_Previews struct that allows you to preview the LayerPreviewer in Xcode's SwiftUI canvas.
In summary, this code allows you to create a SwiftUI view (LayerPreviewer) that can render a CALayer, specifically a CAGradientLayer, and configure its properties using a callback closure.
It uses UIKit's DrawerView as an intermediate layer-based view within the SwiftUI hierarchy to achieve this.
This can be useful for incorporating Core Animation layers within your SwiftUI views.
 
notion image

Discussion (0)

Related Posts