【问题标题】:SwiftUI - Unable to change color of Image iconSwiftUI - 无法更改图像图标的颜色
【发布时间】:2020-05-15 08:29:34
【问题描述】:

我正在尝试构建自己的自定义标签栏视图,但在构建自定义按钮时,我无法更改 Image() 的颜色。

struct TabBarButton: View {
      let title: String
      let icon: String


      var body: some View {
        return GeometryReader{ geometry in
           VStack {
            Image(self.icon)
              .resizable()
              .aspectRatio(contentMode: .fit)
              .frame(width: geometry.size.width/2, height: CGFloat(25))
              .foregroundColor(.white)

            Text(self.title)
                .font(.system(size: 8))
                .foregroundColor(Color.white)
          }
      }
    }

  }

我尝试过foregroundColor(Color.white)、accentColor(Color.white) 和一些不同的颜色倍增器。除了默认黑色之外,还有什么原因吗?简单的解决方法就是获得白色图标,但希望我现在能解决这个问题。

【问题讨论】:

    标签: swiftui


    【解决方案1】:

    我不确定你想要实现什么,但可能你只需要模板渲染模式,比如

    Image(self.icon)
        .renderingMode(.template)
        .foregroundColor(.white)
    

    【讨论】:

    • 是的,这很完美,我只是想动态更改自定义选项卡按钮的颜色。这样我可以在选择时交换颜色而不是交换图标。
    • 我不知道我必须设置.foregroundColor()。我假设一旦设置了renderingMode,它就会自动使用Color.accentColor。每当我将Image 视图作为Button 的标签时,它就可以做到这一点,但如果没有按钮,Image 需要设置.foregroundColor()
    【解决方案2】:

    在导入图标的资产中(从*.pdf导入),设置图像集→渲染为→模板图像

    在代码中:

    Image("ImageFileName")
    

    或者: 您可以添加“模板”后缀并将“Rednder 设置为默认值”。在documentation

    如果图片名称以“模板”结尾,则将图片用作 模板,否则将其渲染为原始图像

    在代码中:

    Image("ImageFileNameTemplate")
    

    【讨论】:

    • 感谢您的解决方案
    【解决方案3】:

    你正在制作一些看起来和行为应该像按钮的东西。为什么不从一开始就让它成为一个按钮,这样你就可以在任何你喜欢的地方重复使用这种按钮?

    struct TabBarButton: ButtonStyle {
        var icon: String = "" // you a free to provide a reasonable default
        
        func makeBody(configuration: Self.Configuration) -> some View {
            GeometryReader{ geometry in
                VStack {
                    Image(systemName: icon)
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: geometry.size.width/2, height: CGFloat(25)) // I didn't put therse magic numbers here
                        .foregroundColor(.green) // not very stylish but the color is a at your control
                    
                    configuration.label
                        .font(.system(size: 8)) // and here
                        .foregroundColor(Color.black)
                }
            }
        }
    }
    

    像往常一样使用带有titleaction {} 的按钮。

        Button("Tab Bar Button") {
            // action code here
        }
        .buttonStyle(TabBarButton(icon: "info.circle"))
    

    以下是向导航栏添加自定义按钮的示例:

    struct TabBarButton: PrimitiveButtonStyle {
        var icon: String = "" // you a free to provide a reasonable default
        func makeBody(configuration: Self.Configuration) -> some View {
            VStack {
                Image(systemName: icon)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .foregroundColor(.green) // Changes color in NavBar
                configuration.label
                    .foregroundColor(Color.black)
            }
        }
    }
    

    并在ContentView 中添加:

        .navigationBarItems(trailing: Button(action: {}, label: {
            Text("Some")
        }).buttonStyle(TabBarButton(icon: "info.circle")))
    

    结果如下所示:

    【讨论】:

    • 当时可能有理由避免这种情况,但这是自定义按钮的推荐实现方式。但是,这不包括使用 .renderingMode(.template) 的修复,这一直是更大的问题。
    【解决方案4】:

    此代码将为图像添加任何颜色,只需使用颜色名称更改名称

    Image("Name")
        .resizable()
        .foregroundColor(Color.name)
    

    【讨论】:

    • 在问题中我已经尝试过这个“我已经尝试过foregroundColor(Color.white)”。除非 Swiftui 发生了变化,否则我不得不使用 .renderingMode(.template) 来解决这个问题。
    【解决方案5】:

    iOS 15+

    有些符号有多层。您需要使用.symbolRenderingMode(.palette) 并使用.foregroundStyle() 视图修饰符显式设置每个图层的颜色

         Image(systemName: "cloud.sun.fill")
                .symbolRenderingMode(.palette)
                .foregroundStyle(.black, .yellow)
    

    【讨论】:

      【解决方案6】:

      代码如下:

      Image("profile_photo").resizable()
      .renderingMode(.template)
      .foregroundColor(.blue)
      .scaledToFill() 
      .frame(width: 120, height: 120,alignment: .center)
      .clipShape(Circle())
      

      【讨论】:

      • 使用 UIImage 作为源时效果很好