I have the following arc:
struct Arc : Shape
{
@Binding var endAngle: Double
var center: CGPoint
var radius: CGFloat
func path(in rect: CGRect) -> Path
{
var path = Path()
path.addArc(center: center, radius: radius, startAngle: .degrees(270), endAngle: .degrees(endAngle), clockwise: false)
return path.strokedPath(.init(lineWidth: 50, lineCap: .round))
}
}
How can I add shadow, similar to the activity arcs on Apple Watch, such that at full circle the endAngle is still discernible?
EDIT: There's the additional issue at 360+ degrees (so full circle), that both arc ends get combined and are shown as a radial line (I see this because I've a applied an AngularGradient
). Of course Arc
won't do advanced things like continuing above the startAngle
position, like the Apple Watch arcs do. But this was what I was looking for. Does anyone know how to do that in SwiftUI?
what about this? ok...bit "tricky"
import SwiftUI
struct Arc : Shape
{
@Binding var startAngle: Double
@Binding var endAngle: Double
var center: CGPoint
var radius: CGFloat
var color: Color
func path(in rect: CGRect) -> Path
{
var path = Path()
let cgPath = CGMutablePath()
cgPath.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: true)
// path.addArc(center: center, radius: radius, startAngle: .degrees(270), endAngle: .degrees(endAngle), clockwise: false)
path = Path(cgPath)
return path.strokedPath(.init(lineWidth: 50, lineCap: .round))
}
}
struct ContentView: View {
var body: some View {
ZStack() {
// Arc(endAngle: .constant(269), center: CGPoint(x: 200, y: 200), radius: 150, color: .red).foregroundColor(.red).opacity(0.2)
Arc(startAngle: .constant(80 + 271), endAngle: .constant(80 + 271 + 340), center: CGPoint(x: 205, y: 205), radius: 150, color: .red).foregroundColor(.red)//.shadow(color: .black, radius: 5, x: -30, y: -170)
Arc(startAngle: .constant(90), endAngle: .constant(80 + 270), center: CGPoint(x: 200, y: 200), radius: 150, color: .red).foregroundColor(.red).shadow(color: .black, radius: 5, x: -114, y: -230)
}.background(Color.black)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
do you mean something like this?
struct Arc : Shape
{
@Binding var endAngle: Double
var center: CGPoint
var radius: CGFloat
var color: Color
func path(in rect: CGRect) -> Path
{
var path = Path()
path.addArc(center: center, radius: radius, startAngle: .degrees(270), endAngle: .degrees(endAngle), clockwise: false)
return path.strokedPath(.init(lineWidth: 50, lineCap: .round))
}
}
struct ContentView: View {
var body: some View {
ZStack() {
Arc(endAngle: .constant(269), center: CGPoint(x: 200, y: 200), radius: 150, color: .red).foregroundColor(.red).opacity(0.2)
Arc(endAngle: .constant(90), center: CGPoint(x: 200, y: 200), radius: 150, color: .red).foregroundColor(.red)
}
}
}
Hi you can fix and handle all of these features by writing an extension in your project file
import UIKit
extension UIView {
func roundCorners(corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
// MARK: Shadow extension UIView {
func dropShadow(scale: Bool = true) {
layer.masksToBounds = false
layer.shadowColor = UIColor.blue.cgColor
layer.shadowOpacity = 1.0
layer.shadowOffset = CGSize(width: -1.5, height: 3)
layer.shadowRadius = 3
layer.shadowPath = UIBezierPath(rect: bounds).cgPath
layer.shouldRasterize = true
layer.rasterizationScale = scale ? UIScreen.main.scale : 1
}
func dropShadow(color: UIColor, opacity: Float = 0.5, offSet: CGSize, radius: CGFloat = 1, scale: Bool = true) {
layer.masksToBounds = false
layer.shadowColor = color.cgColor
layer.shadowOpacity = opacity
layer.shadowOffset = offSet
layer.shadowRadius = radius
layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
layer.shouldRasterize = true
layer.rasterizationScale = scale ? UIScreen.main.scale : 1
}
func setAnchorPoint(_ point: CGPoint) {
var newPoint = CGPoint(x: bounds.size.width * point.x, y: bounds.size.height * point.y)
var oldPoint = CGPoint(x: bounds.size.width * layer.anchorPoint.x, y: bounds.size.height * layer.anchorPoint.y)
newPoint = newPoint.applying(transform)
oldPoint = oldPoint.applying(transform)
var position = layer.position
position.x -= oldPoint.x
position.x += newPoint.x
position.y -= oldPoint.y
position.y += newPoint.y
layer.position = position
layer.anchorPoint = point
}
class func fromNib<T: UIView>() -> T {
guard let view = Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)?.first as? T else { fatalError() }
return view
}
now in storyboard you can handle shadows or you don't want to, and it's too much, you can use the only part you need.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.