在填充的白色圆圈 (UIButton) 内创建一个黑色细圆圈(未填充)
Creating a thin black circle (unfilled) within a filled white circle (UIButton)
我正在尝试复制 iOS 设备上的默认相机按钮:
我可以创建一个带有黑色按钮的白色圆形按钮。但是,黑色按钮也被填充了,而不仅仅是一个细圆圈。
这是我的(大部分是从不同来源复制并放在一起的,所以代码效率不高)
对象代表按钮,
func applyRoundCorner(_ object: AnyObject) {
//object.layer.shadowColor = UIColor.black.cgColor
//object.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
object.layer.cornerRadius = (object.frame.size.width)/2
object.layer.borderColor = UIColor.black.cgColor
object.layer.borderWidth = 5
object.layer.masksToBounds = true
//object.layer.shadowRadius = 1.0
//object.layer.shadowOpacity = 0.5
var CircleLayer = CAShapeLayer()
let center = CGPoint (x: object.frame.size.width / 2, y: object.frame.size.height / 2)
let circleRadius = object.frame.size.width / 6
let circlePath = UIBezierPath(arcCenter: center, radius: circleRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 2), clockwise: true)
CircleLayer.path = circlePath.cgPath
CircleLayer.strokeColor = UIColor.black.cgColor
//CircleLayer.fillColor = UIColor.blue.cgColor
CircleLayer.lineWidth = 1
CircleLayer.strokeStart = 0
CircleLayer.strokeEnd = 1
object.layer.addSublayer(CircleLayer)
}
只需要添加宽度和高度较小的圆形图层即可
试试这个代码
func applyRoundCorner(_ object: UIButton) {
object.layer.cornerRadius = (object.frame.size.width)/2
object.layer.borderColor = UIColor.black.cgColor
object.layer.borderWidth = 5
object.layer.masksToBounds = true
let anotherFrame = CGRect(x: 12, y: 12, width: object.bounds.width - 24, height: object.bounds.height - 24)
let circle = CAShapeLayer()
let path = UIBezierPath(arcCenter: object.center, radius: anotherFrame.width / 2, startAngle: 0, endAngle: .pi * 2, clockwise: true)
circle.path = path.cgPath
circle.strokeColor = UIColor.black.cgColor
circle.lineWidth = 1.0
circle.fillColor = UIColor.clear.cgColor
object.layer.addSublayer(circle)
}
注意:根据您的要求和最佳用户体验更改帧值
输出
基本方法
您可以这样做(出于演示目的,我会使用 playground 以编程方式制作按钮):
let buttonWidth = 100.0
let button = UIButton(frame: CGRect(x: 0, y: 0, width: buttonWidth, height: buttonWidth))
button.backgroundColor = .white
button.layer.cornerRadius = button.frame.width / 2
绘图部分:
因此,在添加按钮并进行所需的设置(使其成为圆形)之后,这里是您可以在其中绘制圆圈的部分方法:
let circlePath = UIBezierPath(arcCenter: CGPoint(x: buttonWidth / 2,y: buttonWidth / 2), radius: 40.0, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.cgPath
circleLayer.fillColor = UIColor.clear.cgColor
circleLayer.strokeColor = UIColor.black.cgColor
circleLayer.lineWidth = 2.5
// adding the layer into the button:
button.layer.addSublayer(circleLayer)
可能,circleLayer.fillColor = UIColor.clear.cgColor
是你遗漏的部分。
因此:
回到你的案例:
旁栏提示:
为了实现applyRoundCorner
,我建议让它有只有圆视图的工作,然后创建另一个函数在视图内添加圆.这是为了避免任何命名冲突,这意味着在阅读 "applyRoundCorner" 时我会 而不是 假设它也会在我的视图中添加圆圈!所以:
func applyRoundedCorners(for view: UIView) {
view.layer.cornerRadius = view.frame.size.width / 2
view.layer.borderColor = UIColor.white.cgColor
view.layer.borderWidth = 5.0
view.layer.masksToBounds = true
}
func drawCircle(in view: UIView) {
let circlePath = UIBezierPath(arcCenter: CGPoint(x: view.frame.size.width / 2,y: view.frame.size.width / 2),
radius: view.frame.size.width / 2.5,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = 2.5
button.layer.addSublayer(shapeLayer)
}
现在:
applyRoundedCorners(for: button)
drawCircle(in: button)
这似乎更好。从另一个方面来说,考虑到您希望将视图设为圆形 而无需在其中添加 圆圈,使用分离方法您可以简单地 applyRoundedCorners(for: myView)
而无需添加圆圈在里面。
此外:
如您所见,我将AnyObject
更改为UIView
,这似乎更符合您的情况。所以我们可以做一件很酷的事情:
extension UIView {
func applyRoundedCorners(for view: UIView) {
view.layer.cornerRadius = view.frame.size.width / 2
view.layer.borderColor = UIColor.white.cgColor
view.layer.borderWidth = 5.0
view.layer.masksToBounds = true
}
func drawCircle(in view: UIView) {
let circlePath = UIBezierPath(arcCenter: CGPoint(x: view.frame.size.width / 2,y: view.frame.size.width / 2),
radius: view.frame.size.width / 2.5,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = 2.5
button.layer.addSublayer(shapeLayer)
}
}
现在 applyRoundedCorners
和 drawCircle
都隐式包含在 UIView
中(这意味着 UIButton
),而不是将 button
传递给这些函数,您将能够:
button.applyRoundedCorners()
button.drawCircle()
我相信有一百万种不同的方法可以解决这个问题,这只是一个...
为了简单和速度,我从 UIButton
开始,我可能会考虑实际从 UIImage
开始并简单地设置按钮的图像属性,但这在很大程度上取决于我我正在努力实现
internal extension FloatingPoint {
var degreesToRadians: Self { return self * .pi / 180 }
var radiansToDegrees: Self { return self * 180 / .pi }
}
class RoundButton: UIButton {
override func draw(_ rect: CGRect) {
makeButtonImage()?.draw(at: CGPoint(x: 0, y: 0))
}
func makeButtonImage() -> UIImage? {
let size = bounds.size
UIGraphicsBeginImageContext(CGSize(width: size.width, height: size.height))
defer {
UIGraphicsEndImageContext()
}
guard let ctx = UIGraphicsGetCurrentContext() else {
return nil
}
let center = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
// Want to "over fill" the image area, so the mask can be applied
// to the entire image
let radius = min(size.width / 2.0, size.height / 2.0)
let innerRadius = radius * 0.75
let innerCircle = UIBezierPath(arcCenter: center,
radius: innerRadius,
startAngle: CGFloat(0.0).degreesToRadians,
endAngle: CGFloat(360.0).degreesToRadians,
clockwise: true)
// The color doesn't matter, only it's alpha level
UIColor.red.setStroke()
innerCircle.lineWidth = 4.0
innerCircle.stroke(with: .normal, alpha: 1.0)
let circle = UIBezierPath(arcCenter: center,
radius: radius,
startAngle: CGFloat(0.0).degreesToRadians,
endAngle: CGFloat(360.0).degreesToRadians,
clockwise: true)
UIColor.clear.setFill()
ctx.fill(bounds)
UIColor.white.setFill()
circle.fill(with: .sourceOut, alpha: 1.0)
return UIGraphicsGetImageFromCurrentImageContext()
}
}
nb:这是未优化的!我会考虑缓存 makeButtonImage
的结果并在按钮的 state/size 更改时使它无效,只是要注意
为什么这种方法是 "better" 而不是其他方法?我只想说,不是,而是它创造的,是一个"cut out"的内圈
这对我来说有点挑剔,但我认为它看起来更好,而且是一个更灵活的解决方案,因为您没有 "need" 内圆描边颜色,等等,等等,等等
该解决方案利用了 CoreGraphics CGBlendMode
s
当然我可能会在 PaintCodeApp 中完成所有事情并完成它
我正在尝试复制 iOS 设备上的默认相机按钮:
我可以创建一个带有黑色按钮的白色圆形按钮。但是,黑色按钮也被填充了,而不仅仅是一个细圆圈。
这是我的(大部分是从不同来源复制并放在一起的,所以代码效率不高)
对象代表按钮,
func applyRoundCorner(_ object: AnyObject) {
//object.layer.shadowColor = UIColor.black.cgColor
//object.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
object.layer.cornerRadius = (object.frame.size.width)/2
object.layer.borderColor = UIColor.black.cgColor
object.layer.borderWidth = 5
object.layer.masksToBounds = true
//object.layer.shadowRadius = 1.0
//object.layer.shadowOpacity = 0.5
var CircleLayer = CAShapeLayer()
let center = CGPoint (x: object.frame.size.width / 2, y: object.frame.size.height / 2)
let circleRadius = object.frame.size.width / 6
let circlePath = UIBezierPath(arcCenter: center, radius: circleRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 2), clockwise: true)
CircleLayer.path = circlePath.cgPath
CircleLayer.strokeColor = UIColor.black.cgColor
//CircleLayer.fillColor = UIColor.blue.cgColor
CircleLayer.lineWidth = 1
CircleLayer.strokeStart = 0
CircleLayer.strokeEnd = 1
object.layer.addSublayer(CircleLayer)
}
只需要添加宽度和高度较小的圆形图层即可
试试这个代码
func applyRoundCorner(_ object: UIButton) {
object.layer.cornerRadius = (object.frame.size.width)/2
object.layer.borderColor = UIColor.black.cgColor
object.layer.borderWidth = 5
object.layer.masksToBounds = true
let anotherFrame = CGRect(x: 12, y: 12, width: object.bounds.width - 24, height: object.bounds.height - 24)
let circle = CAShapeLayer()
let path = UIBezierPath(arcCenter: object.center, radius: anotherFrame.width / 2, startAngle: 0, endAngle: .pi * 2, clockwise: true)
circle.path = path.cgPath
circle.strokeColor = UIColor.black.cgColor
circle.lineWidth = 1.0
circle.fillColor = UIColor.clear.cgColor
object.layer.addSublayer(circle)
}
注意:根据您的要求和最佳用户体验更改帧值
输出
基本方法
您可以这样做(出于演示目的,我会使用 playground 以编程方式制作按钮):
let buttonWidth = 100.0
let button = UIButton(frame: CGRect(x: 0, y: 0, width: buttonWidth, height: buttonWidth))
button.backgroundColor = .white
button.layer.cornerRadius = button.frame.width / 2
绘图部分:
因此,在添加按钮并进行所需的设置(使其成为圆形)之后,这里是您可以在其中绘制圆圈的部分方法:
let circlePath = UIBezierPath(arcCenter: CGPoint(x: buttonWidth / 2,y: buttonWidth / 2), radius: 40.0, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.cgPath
circleLayer.fillColor = UIColor.clear.cgColor
circleLayer.strokeColor = UIColor.black.cgColor
circleLayer.lineWidth = 2.5
// adding the layer into the button:
button.layer.addSublayer(circleLayer)
可能,circleLayer.fillColor = UIColor.clear.cgColor
是你遗漏的部分。
因此:
回到你的案例:
旁栏提示:
为了实现applyRoundCorner
,我建议让它有只有圆视图的工作,然后创建另一个函数在视图内添加圆.这是为了避免任何命名冲突,这意味着在阅读 "applyRoundCorner" 时我会 而不是 假设它也会在我的视图中添加圆圈!所以:
func applyRoundedCorners(for view: UIView) {
view.layer.cornerRadius = view.frame.size.width / 2
view.layer.borderColor = UIColor.white.cgColor
view.layer.borderWidth = 5.0
view.layer.masksToBounds = true
}
func drawCircle(in view: UIView) {
let circlePath = UIBezierPath(arcCenter: CGPoint(x: view.frame.size.width / 2,y: view.frame.size.width / 2),
radius: view.frame.size.width / 2.5,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = 2.5
button.layer.addSublayer(shapeLayer)
}
现在:
applyRoundedCorners(for: button)
drawCircle(in: button)
这似乎更好。从另一个方面来说,考虑到您希望将视图设为圆形 而无需在其中添加 圆圈,使用分离方法您可以简单地 applyRoundedCorners(for: myView)
而无需添加圆圈在里面。
此外:
如您所见,我将AnyObject
更改为UIView
,这似乎更符合您的情况。所以我们可以做一件很酷的事情:
extension UIView {
func applyRoundedCorners(for view: UIView) {
view.layer.cornerRadius = view.frame.size.width / 2
view.layer.borderColor = UIColor.white.cgColor
view.layer.borderWidth = 5.0
view.layer.masksToBounds = true
}
func drawCircle(in view: UIView) {
let circlePath = UIBezierPath(arcCenter: CGPoint(x: view.frame.size.width / 2,y: view.frame.size.width / 2),
radius: view.frame.size.width / 2.5,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = 2.5
button.layer.addSublayer(shapeLayer)
}
}
现在 applyRoundedCorners
和 drawCircle
都隐式包含在 UIView
中(这意味着 UIButton
),而不是将 button
传递给这些函数,您将能够:
button.applyRoundedCorners()
button.drawCircle()
我相信有一百万种不同的方法可以解决这个问题,这只是一个...
为了简单和速度,我从 UIButton
开始,我可能会考虑实际从 UIImage
开始并简单地设置按钮的图像属性,但这在很大程度上取决于我我正在努力实现
internal extension FloatingPoint {
var degreesToRadians: Self { return self * .pi / 180 }
var radiansToDegrees: Self { return self * 180 / .pi }
}
class RoundButton: UIButton {
override func draw(_ rect: CGRect) {
makeButtonImage()?.draw(at: CGPoint(x: 0, y: 0))
}
func makeButtonImage() -> UIImage? {
let size = bounds.size
UIGraphicsBeginImageContext(CGSize(width: size.width, height: size.height))
defer {
UIGraphicsEndImageContext()
}
guard let ctx = UIGraphicsGetCurrentContext() else {
return nil
}
let center = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
// Want to "over fill" the image area, so the mask can be applied
// to the entire image
let radius = min(size.width / 2.0, size.height / 2.0)
let innerRadius = radius * 0.75
let innerCircle = UIBezierPath(arcCenter: center,
radius: innerRadius,
startAngle: CGFloat(0.0).degreesToRadians,
endAngle: CGFloat(360.0).degreesToRadians,
clockwise: true)
// The color doesn't matter, only it's alpha level
UIColor.red.setStroke()
innerCircle.lineWidth = 4.0
innerCircle.stroke(with: .normal, alpha: 1.0)
let circle = UIBezierPath(arcCenter: center,
radius: radius,
startAngle: CGFloat(0.0).degreesToRadians,
endAngle: CGFloat(360.0).degreesToRadians,
clockwise: true)
UIColor.clear.setFill()
ctx.fill(bounds)
UIColor.white.setFill()
circle.fill(with: .sourceOut, alpha: 1.0)
return UIGraphicsGetImageFromCurrentImageContext()
}
}
nb:这是未优化的!我会考虑缓存 makeButtonImage
的结果并在按钮的 state/size 更改时使它无效,只是要注意
为什么这种方法是 "better" 而不是其他方法?我只想说,不是,而是它创造的,是一个"cut out"的内圈
这对我来说有点挑剔,但我认为它看起来更好,而且是一个更灵活的解决方案,因为您没有 "need" 内圆描边颜色,等等,等等,等等
该解决方案利用了 CoreGraphics CGBlendMode
s
当然我可能会在 PaintCodeApp 中完成所有事情并完成它