如何在SwiftUI tvOS中检测'Click'手势

问题描述 投票:1回答:1

使用:

  • SwiftUI
  • Swift 5
  • tvOS
  • Xcode版本11.2.1

我只想在下面的URLImage上检测点击手势

JFYI我是Xcode,Swift和SwiftUI的新手(不到3周)。

URLImage(URL(string: channel.thumbnail)!,
                 delay: 0.25,
                 processors: [ Resize(size: CGSize(width:isFocused ?  300.0 : 225.0, height:isFocused ?  300.0 : 225.0), scale: UIScreen.main.scale) ],
                 content:  {
                    $0.image
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .clipped()
        })
            .frame(width: isFocused ?  300.0 : 250.0, height:isFocused ?  300.0 : 250.0)
            .clipShape(Circle())
            .overlay(
                Circle().stroke( isFocused ? Color.white : Color.black, lineWidth: 8))
            .shadow(radius:5)
            .focusable(true, onFocusChange:{ (isFocused) in
                withAnimation(.easeInOut(duration:0.3)){
                    self.isFocused = isFocused
                }
                if(isFocused){
                    self.manager.bannerChannel = self.channel
                    print(self.manager.bannerChannel)
                    self.manager.loadchannelEPG(id: self.channel.id)
                }
            })
            .padding(20)
    }
  • 我发现的唯一解决方法是将其包装在NavigationLink中或按钮,但无法集中在按钮上。
  • [我发现可聚焦对象在Button / NavigationLink上运行,如果我向其添加角半径,但是默认的click动作不运行
  • 此外,tapGesture在tvOS中不可用

由于可以使用手势,也许有一种使用我无法弄清楚的手势的方法。

如果有一种方法可以将焦点放到按钮上(尽管这是最不受欢迎的选择,因为这会改变我想要的外观)。

swift swiftui tvos
1个回答
0
投票

有可能,但不是因为胆小的人。我想出了一个可能对您有所帮助的通用解决方案。我希望在下一个swiftUI更新中,Apple可以为tvOS附加单击事件的更好方法,并且此代码可以移交给它所属的垃圾箱。

有关如何执行此操作的高级解释是,制作一个捕获焦点和单击事件的UIView,然后制作一个UIViewRepresentable,以便swiftUI可以使用该视图。然后将视图添加到ZStack的布局中,以便将其隐藏,但是您可以获取焦点并响应单击事件,就好像用户确实在与您的真实swiftUI组件进行交互一样。]

首先,我需要制作一个捕获事件的UIView。

    class ClickableHackView: UIView {
        weak var delegate: ClickableHackDelegate?

        override init(frame: CGRect) {
            super.init(frame: frame)        
        }

        override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
            if event?.allPresses.map({ $0.type }).contains(.select) ?? false {
                delegate?.clicked()
            } else {
                superview?.pressesEnded(presses, with: event)
            }
        }

        override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
            delegate?.focus(focused: isFocused)
        }

        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }

        override var canBecomeFocused: Bool {
            return true
        }
    }

可点击的委托人:

protocol ClickableHackDelegate: class {
    func focus(focused: Bool)
    func clicked()
}

然后为我的视图添加swiftui扩展名

struct ClickableHack: UIViewRepresentable {
    @Binding var focused: Bool
    let onClick: () -> Void

    func makeUIView(context: UIViewRepresentableContext<ClickableHack>) -> UIView {
        let clickableView = ClickableHackView()
        clickableView.delegate = context.coordinator
        return clickableView
    }

    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<ClickableHack>) {
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }

    class Coordinator: NSObject, ClickableHackDelegate {
        private let control: ClickableHack

        init(_ control: ClickableHack) {
            self.control = control
            super.init()
        }

        func focus(focused: Bool) {
            control.focused = focused
        }

        func clicked() {
            control.onClick()
        }
    }
}

然后,我制作了一个友好的swiftui包装器,这样我就可以传入我希望成为可聚焦和可点击的任何类型的组件

struct Clickable<Content>: View where Content : View {
    let focused: Binding<Bool>
    let content: () -> Content
    let onClick: () -> Void

    @inlinable public init(focused: Binding<Bool>, onClick: @escaping () -> Void, @ViewBuilder content: @escaping () -> Content) {
        self.content = content
        self.focused = focused
        self.onClick = onClick
    }

    var body: some View {
        ZStack {
            ClickableHack(focused: focused, onClick: onClick)
            content()
        }
    }
}

示例用法:

struct ClickableTest: View {
    @State var focused1: Bool = false
    @State var focused2: Bool = false

    var body: some View {
        HStack {
            Clickable(focused: self.$focused1, onClick: {
                print("clicked 1")
            }) {
                Text("Clickable 1")
                    .foregroundColor(self.focused1 ? Color.red : Color.black)
            }
            Clickable(focused: self.$focused2, onClick: {
                print("clicked 2")
            }) {
                Text("Clickable 2")
                    .foregroundColor(self.focused2 ? Color.red : Color.black)
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.