TM-SGNL-iOS/SignalUI/Views/BezierPathView.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

73 lines
2.1 KiB
Swift

//
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import UIKit
public class BezierPathView: UIView {
public typealias ShapeLayerConfigurationBlock = (CAShapeLayer, CGRect) -> Void
// Configure the view with this method if it uses a single Bezier path.
public var shapeLayerConfigurationBlock: ShapeLayerConfigurationBlock? {
didSet { updateShapeLayer() }
}
public convenience init(configurationBlock: @escaping ShapeLayerConfigurationBlock) {
self.init(frame: .zero)
shapeLayerConfigurationBlock = configurationBlock
}
public override init(frame: CGRect) {
super.init(frame: frame)
isOpaque = false
isUserInteractionEnabled = false
backgroundColor = .clear
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override var frame: CGRect {
didSet {
guard oldValue.size != frame.size else { return }
updateShapeLayer()
}
}
public override var bounds: CGRect {
didSet {
guard oldValue.size != bounds.size else { return }
updateShapeLayer()
}
}
// This method forces the view to reconstruct its layer content. It shouldn't
// be necessary to call this unless the ConfigureShapeLayerBlocks depend on external
// state which has changed.
private var shapeLayer: CAShapeLayer?
private func updateShapeLayer() {
guard bounds.width > 0 && bounds.height > 0 else { return }
if let shapeLayer {
shapeLayer.removeFromSuperlayer()
}
guard let shapeLayerConfigurationBlock else { return }
let shapeLayer = CAShapeLayer()
shapeLayer.disableAnimationsWithDelegate()
shapeLayerConfigurationBlock(shapeLayer, bounds)
layer.addSublayer(shapeLayer)
self.shapeLayer = shapeLayer
setNeedsDisplay()
}
public override func action(for layer: CALayer, forKey event: String) -> CAAction? {
return nil
}
}