在 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
上更改标题、背景颜色、比例和处理点击操作
我正在尝试更改 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