英文:
UIBezierPath, Draw a curved view in swift
问题
我试图创建一个类似于iPhone刘海的曲线。到目前为止,我尝试绘制了曲线,但对结果不满意。
这是代码:
class CurveView: UIView {
override func draw(_ rect: CGRect) {
addShape()
}
private var shapeLayer: CALayer?
private func addShape() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = createPath()
shapeLayer.strokeColor = UIColor.lightGray.cgColor
shapeLayer.fillColor = UIColor.red.cgColor
shapeLayer.lineWidth = 1
shapeLayer.shadowOffset = CGSize(width: 0, height: 0)
shapeLayer.shadowRadius = 5
shapeLayer.shadowColor = UIColor.gray.cgColor
shapeLayer.shadowOpacity = 0.3
if let oldShapeLayer = self.shapeLayer {
self.layer.replaceSublayer(oldShapeLayer, with: shapeLayer)
} else {
self.layer.insertSublayer(shapeLayer, at: 0)
}
self.shapeLayer = shapeLayer
}
func createPath() -> CGPath {
let height: CGFloat = 20
let path = UIBezierPath()
let centerWidth = self.frame.width / 2
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: (centerWidth - height * 4), y: 0))
path.addCurve(to: CGPoint(x: centerWidth, y: height),
controlPoint1: CGPoint(x: (centerWidth - 44), y: 0), controlPoint2: CGPoint(x: centerWidth - 105, y: height))
path.addCurve(to: CGPoint(x: (centerWidth + height * 4), y: 0),
controlPoint1: CGPoint(x: centerWidth + 105, y: height), controlPoint2: CGPoint(x: (centerWidth + 44), y: 0))
path.addLine(to: CGPoint(x: self.frame.width, y: 0))
path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height))
path.addLine(to: CGPoint(x: 0, y: self.frame.height))
path.close()
return path.cgPath
}
}
我希望中间部分是一条直线而不是圆形形状。此外,中间部分应根据内容的大小动态调整。
英文:
I am trying to create a curve that resembles the iPhone notch. So far, I have attempted to draw the curve, but I am not satisfied with the result.
Here is the code:
class CurveView: UIView {
override func draw(_ rect: CGRect) {
addShape()
}
private var shapeLayer: CALayer?
private func addShape() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = createPath()
shapeLayer.strokeColor = UIColor.lightGray.cgColor
shapeLayer.fillColor = UIColor.red.cgColor
shapeLayer.lineWidth = 1
shapeLayer.shadowOffset = CGSize(width:0, height:0)
shapeLayer.shadowRadius = 5
shapeLayer.shadowColor = UIColor.gray.cgColor
shapeLayer.shadowOpacity = 0.3
if let oldShapeLayer = self.shapeLayer {
self.layer.replaceSublayer(oldShapeLayer, with: shapeLayer)
} else {
self.layer.insertSublayer(shapeLayer, at: 0)
}
self.shapeLayer = shapeLayer
}
func createPath() -> CGPath {
let height: CGFloat = 20
let path = UIBezierPath()
let centerWidth = self.frame.width / 2
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: (centerWidth - height * 4), y: 0))
path.addCurve(to: CGPoint(x: centerWidth, y: height),
controlPoint1: CGPoint(x: (centerWidth - 44), y: 0), controlPoint2: CGPoint(x: centerWidth - 105, y: height))
path.addCurve(to: CGPoint(x: (centerWidth + height * 4), y: 0),
controlPoint1: CGPoint(x: centerWidth + 105, y: height), controlPoint2: CGPoint(x: (centerWidth + 44), y: 0))
path.addLine(to: CGPoint(x: self.frame.width, y: 0))
path.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height))
path.addLine(to: CGPoint(x: 0, y: self.frame.height))
path.close()
return path.cgPath
}
}
I would like the center to be a straight line instead of a circular shape. Additionally, the center should adjust dynamically based on the size of my content.
What I want:
答案1
得分: 1
这段代码是用Swift编写的,它创建了一个自定义的UIView
子类NotchView
,以及一个演示控制器NotchVC
。NotchView
是一个带有特殊形状的视图,该形状是通过使用CGMutablePath
和一系列的弧线来创建的,具体的形状和尺寸由一些属性控制,如cornerRadius
、notchRadius
和notchWidthPercent
。
这段代码中包含了一些视图和布局的操作,以及演示控制器的设置。你可以根据需要修改属性来改变形状和颜色。
如果你需要更多详细信息或有其他问题,请随时提出。
英文:
It's easier to create that shape by using a CGMutablePath
and a series of arcs with .addArc(tangent1End: pt1, tangent2End: pt2, radius: r)
.
Quick example:
class NotchView: UIView {
public var cornerRadius: CGFloat = 24.0 { didSet { setNeedsLayout() } }
public var notchRadius: CGFloat = 12.0 { didSet { setNeedsLayout() } }
public var notchWidthPercent: CGFloat = 1.0 / 3.0 { didSet { setNeedsLayout() } }
public var color: UIColor = .red { didSet { shapeLayer.fillColor = color.cgColor } }
// this allows us to use the "base" layer as a shape layer
// instead of adding a sublayer
lazy var shapeLayer: CAShapeLayer = self.layer as! CAShapeLayer
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
shapeLayer.fillColor = UIColor.red.cgColor
}
override func layoutSubviews() {
super.layoutSubviews()
var pth = CGMutablePath()
let w: CGFloat = bounds.width * (1.0 - notchWidthPercent) * 0.5
var pt1: CGPoint = .zero
var pt2: CGPoint = .zero
pth = CGMutablePath()
// start on left side, midY
pt1 = .init(x: bounds.minX, y: bounds.midY)
pth.move(to: pt1)
// top-left corner
pt1 = .init(x: bounds.minX, y: bounds.minY)
pt2 = .init(x: w, y: bounds.minY)
pth.addArc(tangent1End: pt1, tangent2End: pt2, radius: cornerRadius)
// top-left notch
pt1 = pt2
pt2.x += notchRadius
pt2.y += notchRadius
pth.addArc(tangent1End: pt1, tangent2End: pt2, radius: notchRadius)
// bottom-left notch
pt1 = pt2
pt2.x = bounds.maxX - (w + notchRadius)
pth.addArc(tangent1End: pt1, tangent2End: pt2, radius: notchRadius)
// bottom-right notch
pt1 = pt2
pt2.x += notchRadius
pt2.y -= notchRadius
pth.addArc(tangent1End: pt1, tangent2End: pt2, radius: notchRadius)
// top-right notch
pt1 = pt2
pt2.x = bounds.maxX
pth.addArc(tangent1End: pt1, tangent2End: pt2, radius: notchRadius)
// top-right corner
pt1 = pt2
pt2.y = bounds.maxY
pth.addArc(tangent1End: pt1, tangent2End: pt2, radius: cornerRadius)
// bottom-right corner
pt1 = pt2
pt2.x = bounds.minX
pth.addArc(tangent1End: pt1, tangent2End: pt2, radius: cornerRadius)
// bottom-left corner
pt1 = pt2
pt2.y = cornerRadius
pth.addArc(tangent1End: pt1, tangent2End: pt2, radius: cornerRadius)
// close the path
pth.closeSubpath()
shapeLayer.path = pth
}
}
and a demo controller:
class NotchVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray
let notchView = NotchView()
notchView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(notchView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
notchView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
notchView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
notchView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
notchView.heightAnchor.constraint(equalToConstant: 120.0),
])
// you can change these values from their defaults
// examples:
//notchView.color = .blue
//notchView.cornerRadius = 32
//notchView.notchRadius = 8
//notchView.notchWidthPercent = 0.6
}
}
To get this output:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论