是否可以从视图模型订阅视图的焦点状态?



我目前正在创建一个SwiftUI tvOS UI组件,该组件旨在实现自治(以便于重用(。我们可以把它看作一个小模块。将注入该组件的容器视图需要知道焦点在该组件中的位置。(容器将根据此焦点状态更改其他UI元素(。

我试过了:

  • 在获得焦点的视图上添加修饰符focusable
.focusable(true, onFocusChange: { focused in
if focused {
aClosure() // or a publisher?
}
})

但是按钮样式对焦点状态没有反应。(样式更改如下:view.background(isFocused ? buttonStyle.backgroundColor.active : buttonStyle.backgroundColor.normal),它挂接到@Environment(.isFocused) var isFocused(。

  • 正如您可能指出的,在启动tvOS15时,该方法已被弃用,但建议的替代方案无法满足我的需求。(不过,你可以指出我错了!(
  • .isFocused环境变量(@Environment(.isFocused) var isFocused(在视图修饰符之外似乎不会发生变化(考虑到它的用途,这是有意义的,但我不能100%确定(-我尝试连接焦点的通知,但对于注册到该通知的每个视图,该块将在每次焦点更改时执行。此外,因为我们处理的是structs,所以管理身份比较并不是一件小事,我需要一个来自视图的信息来获得焦点。以下是代码:
NotificationCenter.default.addObserver(forName: UIFocusSystem.didUpdateNotification,
object: nil,
queue: OperationQueue.main) { notification in

if let context = notification.userInfo?["UIFocusUpdateContextKey"] as? UIFocusUpdateContext {
print("[Focus] context next item: (context.nextFocusedItem)")
someCompletionBlock()
}
}
  • 焦点状态(@FocusState(是tvOS 15+,我需要tvOS 14兼容性。此外,我尝试将didSet块挂接到它,但没有被执行。这正常吗

我们认为解决方案可以是创建我们自己的属性包装器,但甚至不清楚如何进行。我想它无论如何都需要监听焦点属性?

一个联合发布者";听";以便将更改传播到正确的容器?的精神

var onFocusPublisher: Publisher<Bool, Never> {
$isFocused // where isFocused is the @Environment var
}

感谢您的任何反馈/建议/可能的答案!

注意:我将-UIFocusLoggingEnabled YES添加到了我的方案的传递参数列表中,并确认视图得到了预期的焦点。

最终起作用的是使用按钮自定义样式体中的onChange(of:perform:)函数。

通过这种方式,视觉行为保持工作(即view.background(isFocused ? buttonStyle.backgroundColor.active : buttonStyle.backgroundColor.normal)对更改做出适当反应,并且我可以使用闭包将焦点状态从该视图传递到容器。

它是一个不推荐使用的tvOS14+neneneba API,这是一个优势。

这种方法的主要缺点是ButtonStyle结构现在有两个职责。现在,我将接受这种不那么干净的方法。

最新更新