在 tvOS 上的 SwiftUI 中更改按钮的颜色

Changing the color of a Button in SwiftUI on tvOS

我正在尝试更改 tvOS 上 SwiftUI Button 的颜色。

修改 background 几乎可以工作,除了您可以看到底层 UIButton 实际上是在背景顶部使用圆形、半透明的图像。这会导致矩形背景位于圆形图像之外的角处出现不同的颜色。

添加.padding强调这个问题:

struct ContentView: View {

    @State
    var selected = false

    var body: some View {

        Button(action: {
            self.selected.toggle()
        }) {
               Text($selected.wrappedValue ? "On":"Off")
                .foregroundColor(.white)
            }.padding(.all)
             .background(self.selected ? Color.green : Color.blue)
        }
    }
}

一个相关的问题是改变 "focus" 视图的颜色,因为我怀疑这与按钮本身是同一个视图,改变了 win 大小和颜色。

带有 UIButton 的 tvOS 中的典型技术是更改按钮图像,但似乎没有任何方法可以访问底层图像 UIButton

这段代码似乎在 iOS 上运行良好,但正如您所展示的,在 tvOS 中,底层的 UIButton 是可见的。我不确定如何获取底层按钮或其图像,但现在看来你可以破解它(直到 Apple 解决问题或提供获取该按钮的方法。)

首先,将内边距向上移动以修改文本,使其正确影响底层按钮。

其次,(这就是 hack)在带有 cornerRadius 的背景修改器之后裁剪视图。只要半径等于或大于底层按钮的半径,它就会剪掉多余的背景。 (当然,你看到的不是绿色,而是半透明按钮图像的灰色叠加绿色的颜色,至少Xcode中是这样显示的。)

struct ContentView: View {

    @State var selected = false

    var body: some View {

        Button(action: {
            self.selected.toggle()
        }) {
            Text($selected.wrappedValue ? "On":"Off")
                .foregroundColor(.white)
                .padding(.all)
        }
        .background(self.selected ? Color.green : Color.blue)
        .cornerRadius(5)
    }
}

同样,我只在 iOS 上检查过,但这应该有所帮助:

struct ContentView: View {

    @State var selected = false

    var body: some View {

        Button(action: { self.selected.toggle() }) {
            Text($selected.wrappedValue ? "On":"Off")
                .foregroundColor(.white)
        }   .padding(.all)
            .background(RoundedRectangle(cornerRadius: 5.0)
                            .fill(self.selected ? Color.green : Color.blue))

    }
}

您可以将任何视图传递给 .background() 修饰符,因此您可能还想尝试在其中放置一个 Image()。

尝试:

button.setBackgroundImage(UIImage.imageWithColor(.lightGray), for: .normal)

你可以为 .focused.highlighted

这是 tvOS 在 Swift 5.5

上的有效解决方案
struct TVButton: View {

// MARK: - Variables
@FocusState private var isFocused: Bool
@State private var buttonScale: CGFloat = 1.0
var title: String?
var bgColor: Color = .white
var action: () -> Void

// MARK: - Body
var body: some View {
    TVRepresentableButton(title: title, color: UIColor(bgColor)) {
        action()
    }
    .focused($isFocused)
    .onChange(of: isFocused) { newValue in
        withAnimation(Animation.linear(duration: 0.2)) {
            buttonScale = newValue ? 1.1 : 1.0
        }
    }
    .scaleEffect(buttonScale)
}
}

struct TVRepresentableButton: UIViewRepresentable {

// MARK: - Typealias
typealias UIViewType = UIButton

// MARK: - Variables
var title: String?
var color: UIColor
var action: () -> Void

func makeUIView(context: Context) -> UIButton {
    let button = UIButton(type: .system)
    button.setBackgroundImage(UIImage(color: color), for: .normal)
    button.setBackgroundImage(UIImage(color: color.withAlphaComponent(0.85)), for: .focused)
    button.setBackgroundImage(UIImage(color: color), for: .highlighted)
    button.setTitle(title, for: .normal)
    button.addAction(.init(handler: { _ in action() }), for: .allEvents)
    
    return button
}

    func updateUIView(_ uiView: UIButton, context: Context) {}
}

extension UIImage {
    public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
    let rect = CGRect(origin: .zero, size: size)
    UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
    color.setFill()
    UIRectFill(rect)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    
    guard let cgImage = image?.cgImage else { return nil }
    self.init(cgImage: cgImage)
}
}

现在您可以在 tvOS

上更改标题、背景颜色、比例和处理点击操作