SwiftUI:为工具栏项设置单独的颜色?

SwiftUI:为工具栏项设置单独的颜色?,swiftui,Swiftui,通常,出于可访问性的原因,我喜欢使用默认颜色选项,但我有一个特定的用例,无法更改单个.toolbar工具栏项的颜色 我可以使用代码段顶部的注释代码覆盖所有工具栏项的颜色,但我想给单个图标上色 import SwiftUI struct ContentView: View { // init() { // UIBarButtonItem.appearance(whenContainedInInstancesOf: [UIToolbar.self]).tintColo

通常,出于可访问性的原因,我喜欢使用默认颜色选项,但我有一个特定的用例,无法更改单个.toolbar工具栏项的颜色

我可以使用代码段顶部的注释代码覆盖所有工具栏项的颜色,但我想给单个图标上色

import SwiftUI

struct ContentView: View {
    
//    init() {
//        UIBarButtonItem.appearance(whenContainedInInstancesOf: [UIToolbar.self]).tintColor = .systemRed
//    }
    
    var body: some View {
        
        NavigationView {
            
            Text("Hello, world!")
                .toolbar {
                    
                    // To be colored RED
                    ToolbarItem(placement: .bottomBar) {
                        Button(action: {}, label: {Label("Icon One", systemImage: "stop.fill")})
                    }
                    
                    // To be colored BLACK
                    ToolbarItem(placement: .bottomBar) {
                        Button(action: {}, label: {Label("Icon Two", systemImage: "play.fill")})
                    }
                    
                }
        }
    }
}

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

看起来所有标准类型(按钮、图像、文本等)都是按工具栏项截取的,并转换为适当的内部表示形式。但是自定义视图(例如基于形状的)。。。事实并非如此。下面是一个可能的方法演示

使用Xcode 12/iOS 14准备并测试演示

和简单的自定义形状按钮

struct ShapeButton<S:Shape>: View {
    var shape: S
    var color: Color
    var action: () -> ()

    @GestureState private var tapped = false
    var body: some View {
        shape
            .fill(color).opacity(tapped ? 0.4 : 1)
            .animation(.linear(duration: 0.15), value: tapped)
            .frame(width: 18, height: 18)
            .gesture(DragGesture(minimumDistance: 0)
                .updating($tapped) { value, state, _ in
                    state = true
                }
                .onEnded { _ in
                    action()
                })
    }
}
struct ShapeButton:视图{
变量形状:S
颜色:颜色
变量作用:()->()
@GestureState private var=false
var body:一些观点{
形状
.填充(颜色).不透明度(抽头?0.4:1)
.animation(.linear(持续时间:0.15),值:点击)
.框架(宽度:18,高度:18)
.手势(牵引力(最小距离:0)
.正在更新($tapped){value,state,uuu中
状态=真
}
.onEnded{uuin
行动()
})
}
}

如果你进入UIKit,它对我有效

struct ButtonRepresentation: UIViewRepresentable {
    let sfSymbolName: String
    let titleColor: UIColor
    let action: () -> ()
    
    func makeUIView(context: Context) -> UIButton {
        let b = UIButton()
        let largeConfig = UIImage.SymbolConfiguration(scale: .large)
        let image = UIImage(systemName: sfSymbolName, withConfiguration: largeConfig)
        b.setImage(image, for: .normal)
        b.tintColor = titleColor
        b.addTarget(context.coordinator, action: #selector(context.coordinator.didTapButton(_:)), for: .touchUpInside)
        return b
    }
    
    func updateUIView(_ uiView: UIButton, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(action: action)
    }
    
    typealias UIViewType = UIButton
    
    class Coordinator {
        let action: () -> ()
        
        @objc
        func didTapButton(_ sender: UIButton) {
            self.action()
        }
        
        init(action: @escaping () -> ()) {
            self.action = action
        }
    }
}
然后,您可以添加不同颜色的单独按钮演示文稿

.toolbar {
    ToolbarItem(placement: .cancellationAction) {
        ButtonRepresentation(sfSymbolName: closeIcon, titleColor: closeIconColor) { 
        presentationMode.wrappedValue.dismiss()
    }
}

我找到的最简单的解决方案是放弃
按钮
,改用
.ontapsignate

struct ContentView: View {
    
    var body: some View {
        NavigationView {
            Text("Hello World!")
                .toolbar {
                    
                    // To be colored RED
                    ToolbarItem(placement: .bottomBar) {
                        Label("Icon One", systemImage: "stop.fill")
                            .foregroundColor(.red)
                            .onTapGesture {
                                // Respond to tap
                            }
                    }
                    
                    // To be colored BLACK
                    ToolbarItem(placement: .bottomBar) {
                        Label("Icon One", systemImage: "play.fill")
                            .foregroundColor(.black)
                            .onTapGesture {
                                // Respond to tap
                            }
                    }
                    
                }
        }
    }
}
输出:


是的,我一直在为同样的事情挣扎。看起来,
按钮
使用的是系统着色颜色及其整体样式

以下是我的看法:

content
    .toolbar {
        ToolbarItem(placement: .navigationBarLeading) {
            HStack {
                StyledButton(image: .system("arrow.left")) { ... }
                Spacer(minLength: 0)    // important to not fell button to default styling
            }
        }
    }

这样做的目的不是只显示按钮,而是与其他UI元素一起显示。在我看来,这是一个迅捷的错误。(或者只是想让你聪明一点。)

ToolbarItem似乎忽略了.ontaps手势。换句话说,我认为你的解决方案行不通。颜色会正确更改,但新的“按钮”不会调用任何操作。此外,标签不会像普通按钮那样在点击过程中变暗。
content
    .toolbar {
        ToolbarItem(placement: .navigationBarLeading) {
            HStack {
                StyledButton(image: .system("arrow.left")) { ... }
                Spacer(minLength: 0)    // important to not fell button to default styling
            }
        }
    }