无法对子帽形状进行“分类”。如果需要其他帽形,则必须手动构造形状的轮廓。
我刚刚了解到标准苹果.round
端盖
let l = CAShapeLayer()
l.path = .. just a straight line, say 50 long
l.lineWidth = wahtever, say "20"
l.lineCap = .round
实际上不是圆形的。>。
仔细一看,就会看到。
更像是“屁股”。
因此,对于例如20的线宽,端盖的高度约为7或8
-对于“精确的半圆”,它不是10,正如您所期望的。 >上限。[我很欣赏我可以建立自己的“线”(即“外部”或线)并填充它,然后我可以完全按照自己的意愿设置端盖。
但是有某种方法可能以某种方式将“ endcap”子类化吗?!
如果可以将“线条/厚度”隐喻保留在形状图层中,而不是仔细绘制线条轮廓,则容易得多。
如果你说= .myHappyEndcapMode
,那将是神奇的>
我们如何解决这种令人震惊的情况?
您可以看到这里有多远:
[我刚刚了解到,标准的Apple .round端帽让l = CAShapeLayer()l.path = ..只是一条直线,例如50长l.lineWidth = wahtever,说“ 20” l.lineCap = .round实际上不是圆的。...
无法对子帽形状进行“分类”。如果需要其他帽形,则必须手动构造形状的轮廓。
圆帽已经和CGPath(ellipseIn:)
创建的圆完全一样。
这是在半径稍大的圆上绘制的圆形线,放大了8倍:
线帽的曲率恰好在圆的水平中心开始。
这里是代码:
import UIKit import PlaygroundSupport let lineWidth: CGFloat = 20 let circleRadius = lineWidth / 2 + 1 let lineLayer = CAShapeLayer() lineLayer.position = .init(x: 30, y: 30) let path = CGMutablePath() path.move(to: .zero) path.addLine(to: .init(x: 30, y: 0)) lineLayer.path = path lineLayer.lineWidth = lineWidth lineLayer.lineCap = .round lineLayer.strokeColor = UIColor.gray.cgColor lineLayer.fillColor = nil let circleLayer = CAShapeLayer() circleLayer.position = lineLayer.position circleLayer.path = CGPath(ellipseIn: CGRect.zero.insetBy(dx: -circleRadius, dy: -circleRadius), transform: nil) circleLayer.fillColor = UIColor.blue.cgColor let view = UIView(frame: .init(x: 0, y: 0, width: 100, height: 80)) view.layer.backgroundColor = UIColor.white.cgColor view.layer.addSublayer(circleLayer) view.layer.addSublayer(lineLayer) PlaygroundPage.current.liveView = view
如您所见,圆形的端盖的半径为精确
8个像素。这是我用来获得上述放大图像的实际屏幕截图。线宽从1到10:
编辑
Hmmm ...好像是A)
它是光学的,您没有在放大的图像中算出所有抗锯齿像素(也就是说,当端盖is圆时,只是没有[[look向您舍去),或B)也许您正在缩放/拉伸图像/图层?[这里有几张示例图像-这次,我使用CAShapeLayer
作为覆盖在CAGradientLayer
上的UIImageView
上的遮罩:用于放大图像的屏幕盖:
和生成该视图的源,如果您想使用它:
class GradientView: UIView { override open class var layerClass: AnyClass { return CAGradientLayer.classForCoder() } lazy var gradientLayer: CAGradientLayer = { return self.layer as! CAGradientLayer }() override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() } func commonInit() -> Void { if let l = layer as? CAGradientLayer { let c1 = UIColor(rgb: 0x6119D2) let c2 = UIColor(rgb: 0x7E1CC6) l.colors = [c1.cgColor, c2.cgColor] l.startPoint = CGPoint(x: 0.0, y: 0.0) l.endPoint = CGPoint(x: 1.0, y: 0.0) } } override func layoutSubviews() { super.layoutSubviews() let l = CAShapeLayer() let bez = UIBezierPath() let xOffset = bounds.size.height * 0.5 + 4 bez.move(to: CGPoint(x: xOffset, y: bounds.size.height * 0.5)) bez.addLine(to: CGPoint(x: bounds.size.width - xOffset, y: bounds.size.height * 0.5)) l.lineCap = .round l.lineWidth = bounds.size.height l.strokeColor = UIColor.black.cgColor l.path = bez.cgPath self.layer.mask = l } } class EndCapViewController: UIViewController { let gView: GradientView = { let v = GradientView() v.translatesAutoresizingMaskIntoConstraints = false return v }() let imgView: UIImageView = { let v = UIImageView() v.translatesAutoresizingMaskIntoConstraints = false v.contentMode = .scaleAspectFit return v }() override func viewDidLoad() { super.viewDidLoad() if let img = UIImage(named: "clouds") { imgView.image = img } view.addSubview(imgView) view.addSubview(gView) let lineThickness: CGFloat = 8.0 NSLayoutConstraint.activate([ imgView.centerXAnchor.constraint(equalTo: view.centerXAnchor), imgView.centerYAnchor.constraint(equalTo: view.centerYAnchor), imgView.widthAnchor.constraint(equalToConstant: 128.0), imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor, multiplier: 1.0), gView.widthAnchor.constraint(equalTo: imgView.widthAnchor, multiplier: 1.0), gView.heightAnchor.constraint(equalToConstant: lineThickness), gView.centerXAnchor.constraint(equalTo: imgView.centerXAnchor), gView.centerYAnchor.constraint(equalTo: imgView.centerYAnchor), ]) } } extension UIColor { convenience init(red: Int, green: Int, blue: Int) { assert(red >= 0 && red <= 255, "Invalid red component") assert(green >= 0 && green <= 255, "Invalid green component") assert(blue >= 0 && blue <= 255, "Invalid blue component") self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0) } convenience init(rgb: Int) { self.init( red: (rgb >> 16) & 0xFF, green: (rgb >> 8) & 0xFF, blue: rgb & 0xFF ) } }
无法对子帽形状进行“分类”。如果需要其他帽形,则必须手动构造形状的轮廓。
我想知道您是否看到我们不是...
这里是行尾,宽度为8点(在iPhone 8上以16像素渲染),放大到3200%