如何将阴影应用于 SwiftUI 中的内部视图?

How to apply shadow to interior views in SwiftUI?

我在 VStack 周围添加了一个阴影,它包含我的两个文本字段和一个提交按钮。但是,阴影也应用于 VStack 内的两个文本字段。

是不是我遗漏了什么导致了这种情况的发生?我尝试在文本字段上添加 shadow(radius: 0),但它没有任何改变。如果我从文本字段中删除填充和背景,那么阴影就会消失。

var body: some View {
    VStack() {
        Spacer()

        VStack() {
            TextField($email, placeholder: Text("email"))
                .padding()
                .background(Color(red: 242 / 255, green: 242 / 255, blue: 242 / 255))

            SecureField($password, placeholder: Text("password"))
                .padding()
                .background(Color(red: 242 / 255, green: 242 / 255, blue: 242 / 255))

            Button(action: { self.login() }, label: { Text("Login").foregroundColor(Color.white) })
                .padding()
                .background(Color(red: 0, green: 116 / 255, blue: 217 / 255))
        }
        .padding()
        .background(Color.white)
        .shadow(radius: 10)

        Spacer()
    }
    .padding()
    .background(Color(red: 0, green: 116 / 255, blue: 217 / 255))
    .edgesIgnoringSafeArea(.all)
}

您可以在此处使用 clipped() 来解决此问题

VStack() {
    Text("Text")
        .background(Color.red)
        .padding()
        .padding()

    Text("Text")
        .background(Color.purple)
        .padding()
}
.padding()
.background(Color.white)

.clipped()
.shadow(color: Color.red, radius: 10, x: 0, y: 0)

输出:

希望对您有所帮助:)

您可以通过使用 ZStackVStack 后面放置 RectangleCapsuleCircle 或其他形状来解决此问题。然后将修改器应用于形状而不是 VStack 本身。

ZStack() {
    Capsule()
        .frame(width: 50, height: 50)
        .background(Color.white)
        .shadow(radius: 10)

    VStack() {
        //...
    }
}

对我来说这似乎是一个非常烦人的功能,很多时候您想要在容器上添加阴影而不是将其应用于所有元素。

如果谁知道更好的方法请分享,谢谢!

对我来说,它也可以将阴影应用于背景而不是堆栈,例如:

VStack {
  // ...
}.background(Rectangle().fill(Color.white).shadow(radius: 8))

对于正在为 RoundedRectangle 努力工作的用户,请使用:

HStack {
 // Your nested views
}
.overlay(
  RoundedRectangle(cornerRadius: 10)
   .stroke(Color.black.opacity(0.2), lineWidth: 1)
)
.background(
   RoundedRectangle(
     cornerRadius: 10
   )
   .foregroundColor(Color.white)
   .shadow(
     color: Color.black,
     radius: 5,
     x: 0,
     y: 0
   )
)

阴影应用于 .backgroundRoundedRectagle 元素 shadow

虽然很冗长,但很容易阅读,同样的原则可以应用于任何其他形状。

为此有一个专用修饰符 - compositingGroup

来自文档:

/// Wraps this view in a compositing group.
///
/// A compositing group makes compositing effects in this view's ancestor
/// views, such as opacity and the blend mode, take effect before this view
/// is rendered.
/// [...] 
/// This limits the scope of [...] change to the outermost view.
VStack {
    Text("Text")
        .background(Color.red)
        .padding()
        .padding()
    Text("Text")
        .background(Color.purple)
        .padding()
}
.padding()
.background(Color.white)
.compositingGroup()
.shadow(color: Color.red, radius: 10, x: 0, y: 0)

你好,我目前只使用这个,但它达到了它的目的 - 让我有内阴影。

稍加修改即可得到你想要的。

private struct InnerShadow: ViewModifier {

    func body(content: Content) -> some View {
        HStack(spacing: .zero) {
            verticalLine().offset(x: -1)
            VStack(spacing: .zero) {
                horizontalLine().offset(y: -1)
                content
                horizontalLine().offset(y: 1)
            }
            verticalLine().offset(x: 1)
        }

    }

    private func verticalLine() -> some View {
        Rectangle()
            .foregroundColor(.white)
            .frame(maxWidth: 1, maxHeight: .infinity)
            .shadow(radius: 4)

    }

    private func horizontalLine() -> some View {
        Rectangle()
            .foregroundColor(.white)
            .frame(maxWidth: .infinity, maxHeight: 1)
            .shadow(radius: 4)
    }

}

在某些情况下,使用 .clipped()(如其他一些答案所建议的那样)可能会导致一些不受欢迎的 side-effects。使用 .background() 绘制额外的视图并给出阴影是低效的(在计算方面)且乏味。

最好的方法是在您的 VStack 上调用 .compositingGroup()。看起来像这样:

VStack {
    // Some inner views
}
.compositingGroup()

来自 Apple 开发者文档的 this page

A compositing group makes compositing effects in this view’s ancestor views, such as opacity and the blend mode, take effect before this view is rendered.

因为视图及其子视图合成为一个 View,任何应用于它的阴影都不会传播到子视图。