简体   繁体   English

如何在 SwiftUI 中淡化 SF 符号的顶部或底部边缘?

[英]How Do I Fade the Top or Bottom Edge of a SF Symbol in SwiftUI?

I'm trying to recreate a visual, that consist of 3 SF Symbols.我正在尝试重新创建由 3 个 SF 符号组成的视觉效果。 The image in the middle is 100% solid no fade.中间的图像是 100% 实心不褪色。 I would like to fade top edge of the top most image and fade the bottom edge of the bottom most image.我想淡化最顶部图像的顶部边缘并淡化最底部图像的底部边缘。

I am using SF Symbols.我正在使用 SF 符号。

I would like to reproduce the following:我想重现以下内容:

(fade top of image) (淡入图像顶部)

IMAGE图片

IMAGE图片

IMAGE图片

(fade bottom of image) (淡出图像底部)

How would I accomplish this?我将如何做到这一点?

First, keep in mind that there are usage rules around SF Symbols.首先,请记住,SF 符号有一些使用规则。 It may or may not be allowed to modify them in this way.可能允许也可能不允许以这种方式修改它们。 In particular there is a list of "As-Is" symbols that cannot be used for arbitrary purposes.特别是有一个不能用于任意目的的“原样”符号列表。 But that doesn't change much about the answer.但这并没有改变答案。

The second thing to note is that SF Symbols are a strange beast between text and images.第二要注意的是,SF Symbols 是介于文本和图像之间的一种奇怪的野兽。 They often act like text, and they often draw outside their frames .它们通常表现得像文本,并且经常在框架之外绘制 That creates problems.这会产生问题。 You can fix that by forcing them to be real images as discussed in the linked answer. 您可以通过将它们强制为链接答案中讨论的真实图像来解决此问题。

 
 
 
  
  let config = UIImage.SymbolConfiguration(scale: .large) let image = Image(uiImage: UIImage(systemName:"star.fill", withConfiguration: config)!)
 
 

In the end, as long as you can get an Image that has the correct frame, the rest of this will work. 最后,只要你能得到一个具有正确帧的 Image ,剩下的就可以了。 It doesn't matter that it's a SF Symbol. 它是 SF Symbol 没关系。

Asperi's answer explains how to fix this by using resizable . Asperi 的回答解释了如何通过使用resizable来解决这个问题。

let image = Image(systemName: "star.fill").resizable().aspectRatio(contentMode: .fit)

(I've added aspectRatio so it doesn't distort.) (我添加了aspectRatio所以它不会扭曲。)

First, define your Gradient.首先,定义你的渐变。 This is how the fade will work, and you can configure it with a set of colors or individual color stops.这就是淡入淡出的工作方式,您可以使用一组颜色或单个色标对其进行配置。 The only thing that matters here is the opacity.这里唯一重要的是不透明度。

let fade =  Gradient(colors: [Color.clear, Color.black])

(See Asperi's answer for an example using stops, which give you more control over the fade.) (有关使用停止的示例,请参阅 Asperi 的答案,这使您可以更好地控制渐变。)

With that, you can apply this gradient as a mask:有了它,您可以将此渐变应用为蒙版:

let fade =  Gradient(colors: [Color.clear, Color.black])
let image = Image(systemName: "star.fill")
    .resizable().aspectRatio(contentMode: .fit).frame(height: 48)

struct ContentView: View {
    var body: some View {
        VStack {
            image
                .mask(LinearGradient(gradient: fade, startPoint: .top, endPoint: .bottom))
            image
            image
                .mask(LinearGradient(gradient: fade, startPoint: .bottom, endPoint: .top))
        }
    }
}

This raises issues about sizing.这引发了关于大小的问题。 This approach is a flexible stack.这种方法是一种灵活的堆栈。 It will grow to fill whatever container it's put in. You may want to constrain it a couple of ways.它会长大以填充它放入的任何容器。您可能需要通过几种方式限制它。

First, you can decide the height of the entire stack by putting a frame on it:首先,您可以通过在其上放置一个框架来确定整个堆栈的高度:

    VStack {
        image
            .mask(LinearGradient(gradient: fade, startPoint: .top, endPoint: .bottom))
        image
        image
            .mask(LinearGradient(gradient: fade, startPoint: .bottom, endPoint: .top))
    }.frame(height: 128)
     ^^^^^^^^^^^^^^^^^^^

Or you could fix the size of each image instead:或者您可以改为固定每个图像的大小:

let image = Image(systemName: "star.fill")
    .resizable().aspectRatio(contentMode: .fit).frame(width: 48)
                                               ^^^^^^^^^^^^^^^^^

顶部和底部渐变的三个符号

Here is my alternate (without UIKit usage)这是我的替代品(不使用 UIKit)

在此处输入图像描述

struct TestSFSymbolsFade: View {
    var body: some View {
        VStack {
            Image(systemName: "ant.fill").resizable()
            Image(systemName: "ant.fill").resizable()
            Image(systemName: "ant.fill").resizable()
        }
        .mask(LinearGradient(gradient: Gradient(stops: [
            .init(color: .clear, location: 0),
            .init(color: .black, location: 0.25),
            .init(color: .black, location: 0.75),
            .init(color: .clear, location: 1)
        ]), startPoint: .top, endPoint: .bottom))
        .frame(width: 40, height: 160) // < just for demo, can be any or absent
    }
}

backup 备份

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM