CAShapeLayer 在 XIB swift iOS 中不可见

Posted

技术标签:

【中文标题】CAShapeLayer 在 XIB swift iOS 中不可见【英文标题】:CAShapeLayer not visible in XIB swift iOS 【发布时间】:2018-03-02 12:04:14 【问题描述】:

我正在使用 XIB 文件构建自定义视图。但是,我面临一个问题,即我添加到视图(trackLayer)的图层未显示在 xib 上(circleLayer 是一个动画,我不希望它在 xib 中呈现,据我所知这是不可能的)。 XIB的所有者类代码如下:

@IBDesignable
class SpinningView: UIView 

@IBOutlet var contentView: SpinningView!

//MARK: Properties
let circleLayer = CAShapeLayer()
let trackLayer = CAShapeLayer()

let circularAnimation: CABasicAnimation = 
    let animation = CABasicAnimation()
    animation.fromValue = 0
    animation.toValue = 1
    animation.duration = 2
    animation.fillMode = kCAFillModeForwards
    animation.isRemovedOnCompletion = false
    return animation
()

//MARK: IB Inspectables
@IBInspectable var strokeColor: UIColor = UIColor.red 
    ...


@IBInspectable var trackColor: UIColor = UIColor.lightGray 
    ...


@IBInspectable var lineWidth: CGFloat = 5 
    ...


@IBInspectable var fillColor: UIColor = UIColor.clear 
    ...


@IBInspectable var isAnimated: Bool = true 
    ...


//MARK: Initialization
override init(frame: CGRect) 
    super.init(frame: frame)
    initSubviews()


required init?(coder aDecoder: NSCoder) 
    super.init(coder: aDecoder)

    setup()
    initSubviews()


//MARK: Private functions
private func setup() 
    setupTrack()
    setupAnimationOnTrack()


private func setupTrack()
    trackLayer.lineWidth = lineWidth
    trackLayer.fillColor = fillColor.cgColor
    trackLayer.strokeColor = trackColor.cgColor
    layer.addSublayer(trackLayer)


private func setupAnimationOnTrack()
    circleLayer.lineWidth = lineWidth
    circleLayer.fillColor = fillColor.cgColor
    circleLayer.strokeColor = strokeColor.cgColor
    circleLayer.lineCap = kCALineCapRound
    layer.addSublayer(circleLayer)
    updateAnimation()


private func updateAnimation() 
    if isAnimated 
        circleLayer.add(circularAnimation, forKey: "strokeEnd")
    
    else 
        circleLayer.removeAnimation(forKey: "strokeEnd")
    


//MARK: Layout contraints
override func layoutSubviews() 
    super.layoutSubviews()

    let center = CGPoint(x: bounds.midX, y: bounds.midY)
    let radius = min(bounds.width / 2, bounds.height / 2) - circleLayer.lineWidth / 2

    let startAngle = -CGFloat.pi / 2
    let endAngle = 3 * CGFloat.pi / 2
    let path = UIBezierPath(arcCenter: .zero, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)

    trackLayer.position = center
    trackLayer.path = path.cgPath

    circleLayer.position = center
    circleLayer.path = path.cgPath


private func initSubviews() 
    let bundle = Bundle(for: SpinningView.self)
    let nib = UINib(nibName: "SpinningView", bundle: bundle)
    nib.instantiate(withOwner: self, options: nil)
    contentView.frame = bounds
    addSubview(contentView)


当视图在 Main.storyboard 中被子类化时,我可以看到图像和 tracklayer 如下IB UIView 但是当我转到 XIB 时,它没有 trackLayer(图像周围的圆圈)@987654322 @。虽然有人可能会争辩说它正在工作以及我为什么要为此烦恼,但我认为正确设计 XIB 很重要,因为其他人可能只会将其视为只有图像的视图(不知道动画功能)

【问题讨论】:

【参考方案1】:

当您设计您的 XIB 时,它不是您的@IBDesignable SpinningView实例。实际上,您正在查看SpinningView来源

因此,它背后的代码此时并未运行 - 它仅在您将 SpinningView 的实例添加到另一个视图时运行。

看看这个简单的例子:

@IBDesignable
class SpinningView: UIView 

    @IBOutlet var contentView: UIView!
    @IBOutlet var theLabel: UILabel!

    //MARK: Initialization
    override init(frame: CGRect) 
        super.init(frame: frame)
        initSubviews()
    

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
        initSubviews()
    

    private func initSubviews() 
        let bundle = Bundle(for: SpinningView.self)
        let nib = UINib(nibName: "SpinningView", bundle: bundle)
        nib.instantiate(withOwner: self, options: nil)
        contentView.frame = bounds
        addSubview(contentView)

        // this will change the label's textColor in Storyboard
        // when a UIView's class is set to SpinningView
        theLabel.textColor = .red
    


当我设计 XIB 时,我看到的是这样的:

但是当我将UIView 添加到另一个视图并将其类指定为SpinningView 时,我看到的是:

标签的文本颜色变为红色,因为代码正在运行。

另一种思考方式...您将trackColorfillColor 等变量定义为@IBInspectable。在设计 XIB 时,您不会在 Xcode 的 Attributes Inspector 面板中看到这些属性 - 只有当您选择了已添加到其他位置的 SpinningView 实例时才能看到它们。

希望这是有道理的。

【讨论】:

哇...谢谢。这似乎很有意义,因为我经历过类似的现象。我似乎缺乏关于 IB 警告的知识(老实说,我最近才开始使用 xib)。那么,作为一名程序员,在外面留下一个 xib 是否正确,它只给出了我实际想要实现的部分表示。例如,当另一个程序员接手我的项目时,由于 XIB 应该是可重用的,他/她在查看我的组件时可能会感到困惑,除非他/她深入研究代码 嗯...很难说。我认为,一般来说,人们不会使用 XIB 来开发 @IBDesignable 组件...特别是,当组件的“肉”只能通过代码执行存在时。除非您的 SpinningView 比您所展示的要复杂得多,否则我想我会选择纯代码。我想您可以添加一个在您的 XIB 中可见的有边框、清晰、圆形的视图,然后在您的 XIB 添加到情节提要时将其删除(通过代码)......但这可能会结束无论如何都会变得更加复杂和误导。

以上是关于CAShapeLayer 在 XIB swift iOS 中不可见的主要内容,如果未能解决你的问题,请参考以下文章

CAShapelayer 绘图的橡皮擦功能:SWIFT

CAShapeLayer 不可见

Swift 怎么用xib 自定义View

Swift - 在 Xib 中动态设置 UITableView 高度

如何在 swift 中使用 .xib 创建 UIViewController 子类?

在使用情节提要和 swift 时从 xib 打开 NSWindow