【问题标题】:Changing the color of a Button in SwiftUI on tvOS在 tvOS 上更改 SwiftUI 中按钮的颜色
【发布时间】:2020-01-19 22:03:15
【问题描述】:

我正在尝试在 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)
        }
    }
}

一个相关的问题是改变“焦点”视图的颜色,因为我怀疑这与按钮本身的视图相同,改变了获胜大小和颜色。

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

【问题讨论】:

    标签: swift button swiftui tvos


    【解决方案1】:

    这是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 上更改标题、背景颜色、比例和处理点击操作

    【讨论】:

      【解决方案2】:

      试试:

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

      您可以为.focused.highlighted 设置它

      【讨论】:

      • 这个问题是关于 SwiftUI,而不是 UIKit。正如我在问题中所指出的,如果您可以访问底层 UIButton,您就可以解决问题。
      【解决方案3】:

      同样,我只在 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()。

      【讨论】:

      • 这很好用——我摆脱了.padding(all)——这只是我的问题中强调的问题。我还将半径更改为 8 - 使用 5 我仍然可以看到基本颜色的像素左右。 tvOS 上的 Button 看起来仍然需要 Apple 做一些工作。
      【解决方案4】:

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

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

      第二,(这就是技巧)在背景修饰符之后用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)
          }
      }
      

      【讨论】:

      • 我试过这个,它有几个问题 - 角半径有点猜测 - 如果按钮大于 5 是不够的,但这可以调整。更大的问题是,一旦您将 cornerRadius 应用于按钮,您就无法将其聚焦 - 它变得不可选择。
      • 那么,你比我领先一步。按钮是我无法选择此代码,无论有无cornerRadius。我认为这是 Xcode 中的错误。我不知所措。我也为按钮的标签尝试了一个图像而不是文本,但它在角落有同样的问题。
      • 这种行为很奇怪。在 iOS 中,不能以 Image 作为标签来选择按钮(即使包装在 VStack 中)。但是,它可选择的,其标签为 Text 或同时为 Image 和 Text。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-29
      • 2020-04-16
      • 1970-01-01
      • 1970-01-01
      • 2021-01-23
      • 2019-11-02
      相关资源
      最近更新 更多