如何在 SwiftUI 中使 UIViewRepresentable 在 tvOS 上具有焦点?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中使 UIViewRepresentable 在 tvOS 上具有焦点?【英文标题】:How to make UIViewRepresentable focusable on tvOS in SwiftUI? 【发布时间】:2020-04-23 18:12:40 【问题描述】:

标题说明了一切 - 我无法在 tvOS 上的 SwiftUI 中专注于 UIViewRepresentable。任何符合View 协议的视图都可以毫无问题地聚焦,但UIViewRepresentableUIViewControllerRepresentable 都不能。

有什么想法吗?

此代码有效:

struct ContentView: View 
    var body: some View 
        Text("Hello, World!")
            .focusable()
            .onExitCommand 
                print("Menu button pressed")
        
    

这个没有:

struct ContentView: View 
    var body: some View 
        ViewRepresentable()
            .focusable()
            .onExitCommand 
                print("Menu button pressed")
        
    


struct ViewRepresentable: UIViewRepresentable 
    func makeUIView(context: Context) -> UIView 
        let view = UIView()
        view.backgroundColor = .red

        return view
    

    func updateUIView(_ uiView: UIView, context: Context) 

    

谢谢!

【问题讨论】:

你有什么解决办法吗?我在尝试让 UISearchController 在 SwiftUI 应用程序中工作时遇到同样的问题 @Guy***er 这个有什么更新吗?与UISearchController 有同样的问题 【参考方案1】:

您需要创建一个覆盖 canBecomeFocused 的 UIView 子类以返回 true。如果您想响应焦点,您可能还想覆盖 didUpdateFocus(in:with:)。

作为参考,我制作了一个实用程序类,让我拥有可聚焦的 UIView,并响应远程滑动和点击。

import UIKit

@available (ios, unavailable)
@available (macCatalyst, unavailable)
class UserInputView: UIView 
    weak var pressDelegate: PressableDelegate?
    weak var touchDelegate: TouchableDelegate?
    var touchStarted: CGFloat = 0
    var lastTouch: CGFloat = 0
    
    override init(frame: CGRect) 
        super.init(frame: frame)
    

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
        touchStarted = touches.first?.location(in: nil).x ?? 0
        lastTouch = touchStarted
        touchDelegate?.touchDown()
    
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 
        let thisTouch = touches.first?.location(in: nil).x ?? 0
        touchDelegate?.touchMove(amount: Double((thisTouch - lastTouch)/(touches.first?.window?.frame.width ?? 1920)))
        lastTouch = touches.first?.location(in: nil).x ?? 0
    
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) 
        touchDelegate?.touchUp()
    

    override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) 
        if isClick(presses) 
            pressDelegate?.press(pressed: true)
         else 
            superview?.pressesBegan(presses, with: event)
        
    
    
    override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) 
        if isClick(presses) 
            pressDelegate?.press(pressed: false)
            pressDelegate?.clicked()
         else 
            superview?.pressesEnded(presses, with: event)
        
    
    
    private func isClick(_ presses: Set<UIPress>?) -> Bool 
        return presses?.map( $0.type ).contains(.select) ?? false
    
    
    override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) 
        pressDelegate?.focus(focused: isFocused)
    
    
    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    
    
    override var canBecomeFocused: Bool 
        return true
    

【讨论】:

以上是关于如何在 SwiftUI 中使 UIViewRepresentable 在 tvOS 上具有焦点?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 tvOS 中使 SwiftUI 列表可滚动

如何在 SwiftUI 中使模态不可关闭

如何在 SwiftUI 中使整个列表行成为 NavigationLink

如何在 SwiftUI 中使视图的高度从 0 动画到高度?

如何在 SwiftUI 的新地图视图中制作可点击的图钉?

如何防止工作表在 SwiftUI 中使其后面的视图变暗或删除不必要的填充?