我有带动画的swiftUI选项卡,还有UITabbarViewController,它包含这个swiftUI视图。
SwiftUI
struct MainTabBarView: View {
@ObservedObject var viewModel: MainTabBarViewModel
var body: some View {
VStack {
HStack(spacing: 0) {
TabItem(currentIndex: $viewModel.index, tabIndex: 0, tab: .home)
Spacer()
TabItem(currentIndex: $viewModel.index, tabIndex: 1, tab: .search)
Spacer()
TabItem(currentIndex: $viewModel.index, tabIndex: 2, tab: .library)
}.padding(.top, 8).padding(.leading, 28).padding(.trailing, 28)
.padding(.bottom, 8)
.frame(width: UIScreen.main.bounds.width)
.animation(.easeIn(duration: 0.2))
}
UITabbarViewController:
final class MainTabBarViewController: UITabBarController, Navigatable {
private var viewModel = MainTabBarViewModel()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
bindViewModel()
}
override func viewDidLoad() {
super.viewDidLoad()
configTabBarView()
}
private func configTabBarView() {
let view = UIHostingController(rootView: MainTabBarView(viewModel: viewModel))
addChild(child)
tabBar.addSubview(view.view)
view.didMove(toParent: self)
tabBar.setValue(true, forKey: "hidesShadow")
view.view.snp.makeConstraints { make in
make.leading.trailing.top.equalToSuperview()
make.height.equalTo(100)
}
}
ViewModel:
final class MainTabBarViewModel: NSObject, ObservableObject {
@Published var index: Int = 0
}
这是我的带有选项卡的自定义视图的代码。当我按下选项卡时->视图中的索引此视图中的模型正在更改,然后
struct TabItem: View {
@Binding var currentIndex: Int
var tabIndex: Int
var isCurrentTab: Bool {
return currentIndex == tabIndex
}
var tab: Tabs
var body: some View {
HStack {
Image(uiImage: tab.icon).resizable().frame(width: 25, height: 25, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
.foregroundColor(isCurrentTab ? R.color.primaryColor()!.swiftUI : R.color.grayScaleDark()!.swiftUI)
Text(isCurrentTab ? tab.title : "").font(Font(R.font.poppinsRegular(size: 16)! as CTFont))
.foregroundColor(isCurrentTab ? R.color.primaryColor()!.swiftUI : R.color.grayScaleDark()!.swiftUI)
}.padding(15)
.onTapGesture {
self.currentIndex = tabIndex
logWarn(String(tabIndex))
}
.background(self.tabIndex == currentIndex ? Color(R.color.pink()!) : Color.white)
.frame(height: 44.0)
.cornerRadius(22.0)
.clipped()
}
}
索引正在更改,但选项卡不更新视图的问题。它看起来像是视图不更新。
尽管编译给定的代码会很有帮助,但我认为我已经拼凑出了一个解决方案,允许当前索引保留在MainTabBarViewModel
中,前提是它打算在未来保存其他内容。我还假设TabItem
应该是足够通用的,不必特别依赖于MainTabVarViewModel
。
我的想法是基于在创建TabItem
时提供当前索引的关键路径。如果不是因为TabItem
更新了当前索引,这就足够简单了。然而,因为它确实更新了它,所以在onTapGesture
闭包中,编译器抱怨它不能通过KeyPath进行写入,因为self
是不可变的。所以…召唤鬼魂大卫·惠勒,我试着通过TabItem.init
中保存的闭包来完成。。。它不存在,所以添加它是解决方案的一部分。
第一个TabItem
成为通用:
struct TabItem<TabBarViewModel: ObservableObject>: View {
@ObservedObject var viewModel: TabBarViewModel
let indexKeyPath: WritableKeyPath<TabBarViewModel, Int>
let tapClosure: (Int) -> Void
// @Binding var currentIndex: Int
var currentIndex: Int { viewModel[keyPath: indexKeyPath] }
...
init(currentIndexIn viewModel: TabBarViewModel, at indexKeyPath: WritableKeyPath<TabBarViewModel, Int>, tabIndex: Int, tab: Tabs)
{
self.viewModel = viewModel
self.indexKeyPath = indexKeyPath
self.tabIndex = tabIndex
self.tab = tab
self.tapClosure = { self.viewModel[keyPath: indexKeyPath] = $0 }
}
这样,除了body
中的这个位之外,TabItem
中的所有内容都可以编译(在删除对未经验证代码的引用之后(
.onTapGesture {
currentIndex = tabIndex
print(String(tabIndex))
}
我将其更改为使用在init
:中保存的闭包
.onTapGesture {
tapClosure(tabIndex)
print(String(tabIndex))
}
然后在MainTabBarView
的body
中创建TabItem
将从更改为:
TabItem(currentIndex: $viewModel.index, tabIndex: 0, tab: .home)
到这个
TabItem(currentIndexIn: viewModel, at: .index, tabIndex: 0, tab: .home)
由于缺少太多代码,我无法编译和测试它,所以这有点像猜测。我删掉了缺失的代码,只是为了消除错误,所以我可以说,至少这个解决方案可以编译。它需要在实际应用程序中进行应用和测试,以验证它是否有效。
无论如何,假设它确实有效,这个解决方案仍然允许将索引保留在可观察对象中,而不依赖于该对象的特定类型。