问题
I have a circular shape which I use CAShapeLayer to draw. Now I want to constraint my button to the leading anchor of the layer but then I get this error "Value of type 'CAShapeLayer' has no member 'leadingAnchor'". How can I fix this. Code:
btnSMSIcon.leadingAnchor.constraint(equalTo: shapeLayer.leadingAnchor, constant: 60).isActive = true
回答1:
AutoLayout deals with views, not layers. If you want to include a layer in your AutoLayout, attach the layer to a view.
(You can create a custom UIView who's content layer is a shape layer, and then place your custom UIView in your storyboard. When you resize the view, the backing layer gets resized too.)
Example code:
class ShapeView: UIView {
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
}
Edit:
Note that if if you use a custom subclass of UIView where the view's layerClass
is a CAShapeLayer
the shape layer will resize if the view resizes, but the path won't get regenerated. You need to tell the view to regenerate it's path if its bounds size changes. One way to do that is to implement viewDidLayoutSubviews()
in the view controller and have viewDidLayoutSubviews()
tell the custom view to rebuild it's path.
Another way to handle it is to add a didSet
to the view's bounds
property and rebuild the shape there.
Edit #2
As an experiment I implemented a ShapeView
as described above. I decided to give it a closure, called createPathClosure
that creates the path it installs in the shape layer, and make it respond to changes in the view's bounds. When the bounds change it invokes the closure to rebuild the path.
The view installs a default closure during initialization, but you can replace the closure when you set up a view controller if you want a different path to be drawn:
class ShapeView: UIView {
//This closure will be called when the view needs to rebuild the path for it's shape layer.
public var createPathClosure: ((ShapeView) -> Void)?
public var lineWidth: CGFloat = 5 {
didSet {
createPathClosure?(self)
}
}
override var bounds: CGRect {
didSet {
createPathClosure?(self)
}
}
//This class variable tells the system what kind of CALayer to create for this view.
//This view's backing layer is a CAShapeLayer.
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
var shape: UIBezierPath? {
didSet {
guard let layer = layer as? CAShapeLayer,
let shape = shape else { return }
layer.path = shape.cgPath
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupShapeLayer()
createPathClosure?(self)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupShapeLayer()
createPathClosure?(self)
}
func setupShapeLayer() {
//Set the stroke color, stroke width, and fill color for the shape layer.
guard let layer = layer as? CAShapeLayer else { return }
layer.strokeColor = UIColor.blue.cgColor
layer.lineWidth = lineWidth
layer.fillColor = UIColor.yellow.cgColor
//Define a placeholder createPathClosure (can be replaced)
createPathClosure = { shapeView in
let center = shapeView.superview?.convert(shapeView.center, to: shapeView) ?? CGPoint.zero
let radius = min(shapeView.bounds.size.width, shapeView.bounds.size.height)/2.0 - shapeView.lineWidth / 2.0
shapeView.shape = UIBezierPath(arcCenter: center,
radius: radius,
startAngle: 0,
endAngle: 2 * CGFloat.pi,
clockwise: true)
}
}
}
来源:https://stackoverflow.com/questions/52802176/value-of-type-cashapelayer-has-no-member-leadinganchor