SwiftUI - 如何在图像上添加前景线性渐变

27

我找不到任何关于如何在SwiftUI中对我拥有的图像的前景进行线性渐变的相关文档。

我已经尝试了以下方式:

Image("IconLoseWeight")
  .frame(width: 30.0, height: 30.0)
  .padding(.leading, 17)
  .foregroundColor(LinearGradient(gradient: Gradient(colors: [.white, .black]), startPoint: .top, endPoint: .bottom))

实际上,上面显示的代码没有显示任何错误,但是它会在顶级Stacks中产生毫无意义的警告,导致代码出现错误(我认为这是Xcode或SwiftUI的一个错误)。如果我移除 foreground 修饰符,代码就可以完美运行。

5个回答

65
那是因为foregroundColor需要一个Color,但LinearGradient是一个符合ShapeStyle和View协议的struct。如果我理解正确,您想用渐变填充图像的不透明区域?
ZStack {
  Color.white // For the background. If you don't need a background, you don't need the ZStack.
  LinearGradient(gradient: Gradient(colors: [.green, .blue]), startPoint: .top, endPoint: .bottom)
    .mask(Image("AssetWithTransparency")
      .resizable()
      .padding()
      .aspectRatio(contentMode: .fit))
  }.cornerRadius(15)

结果看起来像这样:

在此输入图片描述


很棒的解决方案和示例! - Shaun
这段代码拯救了我的生命!非常感谢你,伙计!! - oskarko

29

这里的任务是在图像上显示渐变。为了在SwiftUI中显示一个视图叠加在另一个视图上,可以使用ZStack视图,因此代码可以具有以下结构:

ZStack {
    <Image>
    <Rectangle with gradient>
}

此外,为确保我们使用的图像正确调整大小到指定的框架,应该使用正确的contentMode应用resizable修饰符:

Image("IconLoseWeight")
    .resizable()                     // Make it resizable
    .aspectRatio(contentMode: .fit)  // Specifying the resizing mode so that image scaled correctly

毕竟,我们需要在ZStack上应用frame和填充参数,以使渐变具有与图像相同的大小。

结果将如下所示:

ZStack {
    Image("IconLoseWeight")
        .resizable()                    // Making the image resizable to the container size
        .aspectRatio(contentMode: .fit) // Setting up resizing mode so that the image scaled correctly

    Rectangle()                         // Shapes are resizable by default
        .foregroundColor(.clear)        // Making rectangle transparent
        .background(LinearGradient(gradient: Gradient(colors: [.clear, .black]), startPoint: .top, endPoint: .bottom), cornerRadius: 0)   
                                        // Specifying gradient (note that one color is .clear)
}
.frame(width: 30, height: 30)           // Applying frame
.padding(.leading, 17)                  // Applying padding

请注意,我们使用从.clear.black的渐变色,因为我们需要一个透明的渐变色来使图像可见。

能否从距离顶部100像素的位置开始渐变?这样你就会有一个100像素的纯色,然后从那里开始渐变了吗? - CIB
op想要在前景(颜色)上应用渐变,而不是在背景(视图)上应用。 - slimbikr
我们真的需要Rectangle()吗?我们可以简单地使用Image,然后再使用LinearGradient。 - Sayalee Pote

8

截至最近的SwiftUI版本,最佳方法是使用.foregroundStyle()视图修饰符。我不确定这种方法何时可用,但此代码已在Xcode 14和iOS 16上进行了测试。

以下是示例代码:

let gradient = Gradient(colors: [.purple, .cyan, .orange])

var body: some View {
    Image(systemName: "figure.strengthtraining.traditional")
        .font(.title)
        .foregroundStyle(.linearGradient(gradient, startPoint: .top, endPoint: .bottom))
}

4

我同意@RyuX51的答案,它有效运行。但是,我的图像大小和对齐方式似乎发生了变化。因为LinearGradientframe没有设置。所以,我提供了一个解决方案,只需将渐变应用于Image

VStack{
    Spacer()
    Button(action: {
        print("Add Photos")
    }, label: {

        LinearGradient(gradient: Gradient(colors: [.green, .blue]), startPoint: .top, endPoint: .bottom)
            .mask(Image(systemName: "plus.circle.fill")
            .resizable()
            .aspectRatio(contentMode: .fit)
        ).frame(width: 70, height: 70, alignment: .center)
    })
}

.aspectRatio(contentMode: .fit) 不是必需的,但它很好。完美地工作! - iGhost

3

RyuX51的回答对我有用,但视图最终会拉伸以填充可用空间。我希望它能缩小以适应我使用的图像大小。

这对我的需求很有效:

extension View {
    /// Fills in self with `fill`, maintaining self's natural size
    /// - Parameter fill: View to fill in self with (i.e., a gradient)
    /// - Returns: Filled-in version of self
    @ViewBuilder func filled(with fill: () -> some View) -> some View {
        self.overlay {
            fill().mask { self }
        }
    }
}

例如,代码如下:
Image(systemName: "car.2.fill")
                .font(.system(size: 75))
                .imageScale(.large)
                .aspectRatio(contentMode: .fit)
                .filled {
                    LinearGradient(
                        gradient: Gradient(colors: [.green, .blue]), startPoint: .top, endPoint: .bottom)
                }
                .border(.orange, width: 2)

会给你:

enter image description here


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