使用 TabView 时:
TabView {
ReceivedView()
.badge(2)
.tabItem {
Label("Received", systemImage: "tray.and.arrow.down.fill")
}
SentView()
.tabItem {
Label("Sent", systemImage: "tray.and.arrow.up.fill")
}
AccountView()
.badge("!")
.tabItem {
Label("Account", systemImage: "person.crop.circle.fill")
}
}
但是,我想知道TabView如何识别每个视图?我假设在内部,一些代码会像
ForEach(Content.views) { view in
if view == selectedItem {
view
}
}
但我不知道如何获取 Content.views,有什么想法吗?
我猜测了一点,但我相信它通过 ViewTraitKey 和 VariadicViews 使用标签。
我将尝试复制下面的选择行为
首先我们将定义一些可以帮助我们解决问题的事情。
struct VariadicViewReader<Source: View, Content: View>: View {
var source: Source
var content: Content
init(_ source: Source, @ViewBuilder content: @escaping (_VariadicView.Children) -> Content) {
self.source = source
self.content = content
}
var body: some View {
_VariadicView.Tree(Root(content: content)) { source }
}
}
private struct CustomTagTraitKey: _ViewTraitKey {
static var defaultValue: AnyHashable? = nil
}
extension _VariadicView_Children.Element {
var customTag: AnyHashable? {
self[CustomTagTraitKey.self]
}
func customTag<T: Hashable>(as: T.Type) -> T? {
customTag as? T
}
}
extension View {
func customTag<V: Hashable>(_ tag: V) -> some View {
_trait(CustomTagTraitKey.self, AnyHashable(tag))
}
}
现在设置到位,我们可以创建一个 CustomTabView
struct CustomTabView<SelectionValue, Content>: View where SelectionValue: Hashable> {
@Binding var selection: SelectionValue
let content: Content
init(_ selection: Binding<SelectionValue>, @ViewBuilder content: () -> Content) {
self._selection = selection
self.content = content()
}
var body: some View {
VariadicViewReader(content) { children in
ForEach(children) child in
if let tag = child.customTag(as: SelectionValue.self), tag == selection {
child
}
}
}
}
}
然后使用它就像
CustomTabView($selectedTab) {
View1().customTag(0)
View2().customTag(1)
}
或
CustomTabView($selectedTab) {
ForEach([0, 1], id: \.self) { num
View1().customTag(num)
}
}
这是苹果文档中的相关注释
ForEach 使用相应元素的 id 参数自动将默认标记应用于每个枚举视图。如果元素的 id 参数和选择器的选择输入具有完全相同的类型,则可以省略显式标记修饰符。要查看不需要显式标签的示例,请参阅选取器。
考虑到这一点
TabView {
ForEach([0, 1], id: \.self) { num
View1()
}
}
与
相同TabView {
ForEach([0, 1], id: \.self) { num
View1().tag(num)
}
}