UIBezierPath,在Swift中绘制曲线视图。

huangapple go评论73阅读模式
英文:

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.

UIBezierPath,在Swift中绘制曲线视图。

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:

UIBezierPath,在Swift中绘制曲线视图。

答案1

得分: 1

这段代码是用Swift编写的,它创建了一个自定义的UIView子类NotchView,以及一个演示控制器NotchVCNotchView是一个带有特殊形状的视图,该形状是通过使用CGMutablePath和一系列的弧线来创建的,具体的形状和尺寸由一些属性控制,如cornerRadiusnotchRadiusnotchWidthPercent

这段代码中包含了一些视图和布局的操作,以及演示控制器的设置。你可以根据需要修改属性来改变形状和颜色。

如果你需要更多详细信息或有其他问题,请随时提出。

英文:

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:

UIBezierPath,在Swift中绘制曲线视图。

huangapple
  • 本文由 发表于 2023年3月9日 14:29:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75681120.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定