gpt4 book ai didi

iOS UIView - 4 个角各有不同的圆角半径

转载 作者:行者123 更新时间:2023-12-03 16:52:16 24 4
gpt4 key购买 nike

如何为 UIView 的 4 个角设置完全不同的圆角半径?

UIBezierPath 允许我为一个或多个特定角设置一个值,但不能为每个角设置不同的值。

我认为理论上应该可以使用自定义 CGPath,但我无法实现它。

最佳答案

尝试一下 - 您可以将其直接粘贴到 Playground 页面中,看看它是如何工作的:

import UIKit
import PlaygroundSupport

extension Int {
var degreesToRadians: Double { return Double(self) * .pi / 180 }
}
extension FloatingPoint {
var degreesToRadians: Self { return self * .pi / 180 }
var radiansToDegrees: Self { return self * 180 / .pi }
}

class VariableCornerRadiusView: UIView {

var upperLeftCornerRadius:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

var upperRightCornerRadius:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

var lowerLeftCornerRadius:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

var lowerRightCornerRadius:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}


func layoutMask() -> Void {

var pt = CGPoint.zero

let myBezier = UIBezierPath()

pt.x = upperLeftCornerRadius
pt.y = 0

myBezier.move(to: pt)

pt.x = bounds.width - upperRightCornerRadius
pt.y = 0

myBezier.addLine(to: pt)

pt.x = bounds.width - upperRightCornerRadius
pt.y = upperRightCornerRadius

myBezier.addArc(withCenter: pt, radius: upperRightCornerRadius, startAngle: CGFloat(270.degreesToRadians), endAngle: CGFloat(0.degreesToRadians), clockwise: true)

pt.x = bounds.width
pt.y = bounds.height - lowerRightCornerRadius

myBezier.addLine(to: pt)

pt.x = bounds.width - lowerRightCornerRadius
pt.y = bounds.height - lowerRightCornerRadius

myBezier.addArc(withCenter: pt, radius: lowerRightCornerRadius, startAngle: CGFloat(0.degreesToRadians), endAngle: CGFloat(90.degreesToRadians), clockwise: true)

pt.x = lowerLeftCornerRadius
pt.y = bounds.height

myBezier.addLine(to: pt)

pt.x = lowerLeftCornerRadius
pt.y = bounds.height - lowerLeftCornerRadius

myBezier.addArc(withCenter: pt, radius: lowerLeftCornerRadius, startAngle: CGFloat(90.degreesToRadians), endAngle: CGFloat(180.degreesToRadians), clockwise: true)

pt.x = 0
pt.y = upperLeftCornerRadius

myBezier.addLine(to: pt)

pt.x = upperLeftCornerRadius
pt.y = upperLeftCornerRadius

myBezier.addArc(withCenter: pt, radius: upperLeftCornerRadius, startAngle: CGFloat(180.degreesToRadians), endAngle: CGFloat(270.degreesToRadians), clockwise: true)

myBezier.close()

let maskForPath = CAShapeLayer()
maskForPath.path = myBezier.cgPath
layer.mask = maskForPath

}

override func layoutSubviews() {
super.layoutSubviews()
self.layoutMask()
}

}

var testSize = CGSize(width: 200, height: 200)

// set up an orange view to hold it...
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 260))

containerView.backgroundColor = UIColor.orange

// create a VariableCornerRadiusView, just a little smaller than the container view
let TestView = VariableCornerRadiusView(frame: containerView.bounds.insetBy(dx: 20, dy: 20))

// set different radius for each corner
TestView.upperLeftCornerRadius = 20.0
TestView.upperRightCornerRadius = 40.0
TestView.lowerRightCornerRadius = 60.0
TestView.lowerLeftCornerRadius = 80.0

// give it a blue background
TestView.backgroundColor = UIColor.blue

// add it to the container
containerView.addSubview(TestView)

// show it
PlaygroundPage.current.liveView = containerView

结果应如下所示:

enter image description here

<小时/>

编辑另一种方法...使用填充形状图层(而不是蒙版)和阴影:

import UIKit
import PlaygroundSupport

extension Int {
var degreesToRadians: Double { return Double(self) * .pi / 180 }
}
extension FloatingPoint {
var degreesToRadians: Self { return self * .pi / 180 }
var radiansToDegrees: Self { return self * 180 / .pi }
}

class VariableCornerRadiusShadowView: UIView {

var upperLeftCornerRadius:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

var upperRightCornerRadius:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

var lowerLeftCornerRadius:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

var lowerRightCornerRadius:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

var fillColor: UIColor = .white {
didSet {
self.setNeedsLayout()
}
}

var shadowColor: UIColor = .black {
didSet {
self.setNeedsLayout()
}
}

var shadowOffset: CGSize = CGSize(width: 0.0, height: 2.0) {
didSet {
self.setNeedsLayout()
}
}

var shadowOpacity: Float = 0.5 {
didSet {
self.setNeedsLayout()
}
}

var shadowRadius: CGFloat = 8.0 {
didSet {
self.setNeedsLayout()
}
}

let theShapeLayer = CAShapeLayer()

override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}

func commonInit() -> Void {
layer.addSublayer(theShapeLayer)
}

func layoutShape() -> Void {

var pt = CGPoint.zero

let myBezier = UIBezierPath()

pt.x = upperLeftCornerRadius
pt.y = 0

myBezier.move(to: pt)

pt.x = bounds.width - upperRightCornerRadius
pt.y = 0

myBezier.addLine(to: pt)

pt.x = bounds.width - upperRightCornerRadius
pt.y = upperRightCornerRadius

myBezier.addArc(withCenter: pt, radius: upperRightCornerRadius, startAngle: CGFloat(270.degreesToRadians), endAngle: CGFloat(0.degreesToRadians), clockwise: true)

pt.x = bounds.width
pt.y = bounds.height - lowerRightCornerRadius

myBezier.addLine(to: pt)

pt.x = bounds.width - lowerRightCornerRadius
pt.y = bounds.height - lowerRightCornerRadius

myBezier.addArc(withCenter: pt, radius: lowerRightCornerRadius, startAngle: CGFloat(0.degreesToRadians), endAngle: CGFloat(90.degreesToRadians), clockwise: true)

pt.x = lowerLeftCornerRadius
pt.y = bounds.height

myBezier.addLine(to: pt)

pt.x = lowerLeftCornerRadius
pt.y = bounds.height - lowerLeftCornerRadius

myBezier.addArc(withCenter: pt, radius: lowerLeftCornerRadius, startAngle: CGFloat(90.degreesToRadians), endAngle: CGFloat(180.degreesToRadians), clockwise: true)

pt.x = 0
pt.y = upperLeftCornerRadius

myBezier.addLine(to: pt)

pt.x = upperLeftCornerRadius
pt.y = upperLeftCornerRadius

myBezier.addArc(withCenter: pt, radius: upperLeftCornerRadius, startAngle: CGFloat(180.degreesToRadians), endAngle: CGFloat(270.degreesToRadians), clockwise: true)

myBezier.close()

theShapeLayer.path = myBezier.cgPath
theShapeLayer.fillColor = fillColor.cgColor

layer.shadowRadius = shadowRadius
layer.shadowOffset = shadowOffset
layer.shadowOpacity = shadowOpacity
layer.shadowColor = shadowColor.cgColor

}

override func layoutSubviews() {
super.layoutSubviews()
self.layoutShape()
}

}

var testSize = CGSize(width: 200, height: 200)

// set up an orange "container" view to hold it...
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 260))

containerView.backgroundColor = UIColor.white

let sampleView = VariableCornerRadiusShadowView(frame: containerView.bounds.insetBy(dx: 20, dy: 20))

// set different radius for each corner
sampleView.upperLeftCornerRadius = 20.0
sampleView.upperRightCornerRadius = 40.0
sampleView.lowerRightCornerRadius = 60.0
sampleView.lowerLeftCornerRadius = 80.0

// if we want to adjust defaults
//sampleView.fillColor = .green
//sampleView.shadowOffset = CGSize(width: 2, height: 4)
//sampleView.shadowRadius = 4 // not quite so "fuzzy"
//sampleView.shadowOpacity = 0.8

// add view to container
containerView.addSubview(sampleView)

// show it
PlaygroundPage.current.liveView = containerView

具有“默认”属性的结果:

enter image description here

结果属性更改为:

.fillColor = .green
.shadowOffset = CGSize(width: 2, height: 4)
.shadowRadius = 4 // not quite so "fuzzy"
.shadowOpacity = 0.8

enter image description here

<小时/>

编辑 2 -

此版本现在为@IBDesignable,其中一些属性已重命名,以便在 IB 中更好地显示。还添加了边框宽度和颜色:

@IBDesignable
class VariableCornerRadiusShadowView: UIView {

@IBInspectable
var radTopLeft:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var radTopRright:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var radBotLeft:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var radBotRright:CGFloat = 0 {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var fillColor: UIColor = .white {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var borderColor: UIColor = .clear {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var borderWidth: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var shadowColor: UIColor = .black {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var shadowXOffset: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var shadowYOffset: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var shadowOpacity: Float = 0.5 {
didSet {
self.setNeedsLayout()
}
}

@IBInspectable
var shadowRadius: CGFloat = 8.0 {
didSet {
self.setNeedsLayout()
}
}

let theShapeLayer = CAShapeLayer()

override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func prepareForInterfaceBuilder() {
commonInit()
}

func commonInit() -> Void {
backgroundColor = .clear
layer.addSublayer(theShapeLayer)
}

func layoutShape() -> Void {

var pt = CGPoint.zero

let myBezier = UIBezierPath()

pt.x = radTopLeft
pt.y = 0

myBezier.move(to: pt)

pt.x = bounds.width - radTopRright
pt.y = 0

myBezier.addLine(to: pt)

pt.x = bounds.width - radTopRright
pt.y = radTopRright

myBezier.addArc(withCenter: pt, radius: radTopRright, startAngle: .pi * 1.5, endAngle: 0, clockwise: true)

pt.x = bounds.width
pt.y = bounds.height - radBotRright

myBezier.addLine(to: pt)

pt.x = bounds.width - radBotRright
pt.y = bounds.height - radBotRright

myBezier.addArc(withCenter: pt, radius: radBotRright, startAngle: 0, endAngle: .pi * 0.5, clockwise: true)

pt.x = radBotLeft
pt.y = bounds.height

myBezier.addLine(to: pt)

pt.x = radBotLeft
pt.y = bounds.height - radBotLeft

myBezier.addArc(withCenter: pt, radius: radBotLeft, startAngle: .pi * 0.5, endAngle: .pi, clockwise: true)

pt.x = 0
pt.y = radTopLeft

myBezier.addLine(to: pt)

pt.x = radTopLeft
pt.y = radTopLeft

myBezier.addArc(withCenter: pt, radius: radTopLeft, startAngle: .pi, endAngle: .pi * 1.5, clockwise: true)

myBezier.close()

theShapeLayer.path = myBezier.cgPath
theShapeLayer.fillColor = fillColor.cgColor

theShapeLayer.strokeColor = borderColor.cgColor
theShapeLayer.lineWidth = borderWidth

layer.shadowRadius = shadowRadius
layer.shadowOffset = CGSize(width: shadowXOffset, height: shadowYOffset)
layer.shadowOpacity = shadowOpacity
layer.shadowColor = shadowColor.cgColor

}

override func layoutSubviews() {
super.layoutSubviews()
self.layoutShape()
}

}

关于iOS UIView - 4 个角各有不同的圆角半径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43123774/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com