如何在SwiftUI中对形状的描边应用内阴影?

3
我想在形状的描边上应用内阴影。我找到了一个处理内阴影的函数(无法使用 iOS 16),但我很难将此函数应用于描边本身。
以下是我的代码:
struct ContentView: View {
    var body: some View {
        VStack {
            PolygonShape(sides: 7)
                .stroke(Color.white, lineWidth: 10)
            PolygonShape(sides: 7)
                .innerShadow(color: .red, radius: 10)
        }
        .padding(32)
        .background(Color.black.ignoresSafeArea())
    }
}

extension Shape {
    func innerShadow(color: Color, radius: Double) -> some View {
        overlay(
            stroke(color, lineWidth: radius)
                .blur(radius: radius)
                .mask(self)
        )
    }
}

struct PolygonShape: Shape {
    let sides: Int

    func path(in rect: CGRect) -> Path {
        let c = CGPoint(x: rect.width/2.0, y: rect.height/2.0)
        let r = Double(min(rect.width,rect.height)) / 2.0
        var vertices:[CGPoint] = []
        for i in 0...sides {
            let angle = (2.0 * Double.pi * Double(i)/Double(sides))
            let pt = CGPoint(x: r * cos(angle), y: r * sin(angle))
            vertices.append(CGPoint(x: pt.x + c.x, y: pt.y + c.y))
        }
        var path = Path()
        for (n, pt) in vertices.enumerated() {
            n == 0 ? path.move(to: pt) : path.addLine(to: pt)
        }
        path.closeSubpath()
        return path
    }
}

struct StackedElementsView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

这是它的外观,但不是我想要的:

enter image description here

我希望做的是将内部红色阴影仅放在白色描边上,因此描边只有内部有红色阴影而不在形状中。
类似于这个:

enter image description here

我尝试在颜色本身上应用内阴影,但由于它不是一个形状,所以无法编译:.stroke(Color.white.innerShadow(color: .red, radius: 2) 如何在描边颜色上应用内阴影?

当iOS 16发布时,您可以尝试使用以下链接:https://developer.apple.com/documentation/swiftui/shapestyle/shadow(_:)-swift.type.method/ - aheze
1
我在想这是否能够帮助处理iOS 16上描边的内部阴影,但不幸的是我们还需要支持iOS 15一年。 - TruMan1
你是想让阴影稍微重叠在描边上,还是只是在描边形状后面发光而不重叠? - Stoic
我试图使阴影从描边的边缘向内投射。 - TruMan1
1
换句话说,形状周围或内部不会有阴影。只有描边从其边缘向中间具有红色阴影。描边的中心将是白色的;但它的内部边缘将有阴影向内延伸。 - TruMan1
2个回答

2

这不是最干净或最完整的答案,但它很简单。

在你的 var body 中,下面的代码...

ZStack {
                
    PolygonShape(sides: 7)
        .stroke(Color.white, lineWidth: 10)
                
    PolygonShape(sides: 7)
        .stroke(Color.black, lineWidth: 10)
        .scaleEffect(1.07)
        .shadow(color: .red, radius: 3)
                
    PolygonShape(sides: 7)
        .scaleEffect(0.965)
        .shadow(color: .red, radius: 3)
}

...产生这种类型的边框:

然而,图形周围有一条红线,具体情况可能很容易或很难修复。这只是一个临时答案 :) 或者,如果您可以让形状成为仅边框(没有填充),则可以使用.mask并将其掩蔽为您选择的渐变。


1
尽管不完美,也可能无法处理许多情况,但另一种方法是先绘制描边,然后在其中再绘制一条一半大小的模糊描边。
extension Shape {
    func stroke<Stroke: ShapeStyle>(
        _ content: Stroke,
        lineWidth: Double = 1,
        innerShadow: (color: Color, radius: Double)
    ) -> some View {
        stroke(content, lineWidth: lineWidth / 2)
            .blur(radius: innerShadow.radius)
            .background(stroke(innerShadow.color, lineWidth: lineWidth))
    }
}

PolygonShape(sides: 7)
    .stroke(Color.white, lineWidth: 10, innerShadow: (Color.red, 2))

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接