我有一个像这样的受控选项卡视图
TabView(selection: $activeTab) {
IntroductionView().tag(1)
HomeView().tag(2)
SettingsView().tag(3)
ProfileView().tag(4)
}
我想在
activeTab
变化时为每个视图添加过渡,比如简单的不透明度交叉淡入淡出?
尝试了类似的事情
TabView(selection: $activeTab) {
IntroductionView().tag(1).transition(.opacity)
HomeView().tag(2).transition(.opacity)
SettingsView().tag(3).transition(.opacity)
ProfileView().tag(4).transition(.opacity)
}
.animation(.smooth, value: activeTab)
但这似乎没有效果。有一些像thisone这样的答案通过
.tabViewStyle(.page(indexDisplayMode: .never))
添加某种可滚动/幻灯片动画
修改器,但这并不完全是我想要的。
也许有一种方法可以利用/扩展 UIKit 来添加交叉淡入淡出过渡?
如果您希望能够使用视图修饰符为每个选项卡指定
Transition
(就像在示例代码中所做的那样),最好编写自己的 TabView
。
这是我在here编写的自定义“选项卡视图”的改编版本,它使选项卡看起来更像选项卡。我还添加了
tabTransition
修饰符,让您可以选择 Transition
。请注意,这取决于 View Extractor。
struct CustomTabView<Content: View, Selection: Hashable>: View {
@Binding var selectedTab: Selection
@ViewBuilder let content: () -> Content
var body: some View {
Extract(content) { views in
ForEach(views) { view in
if view.id(as: Selection.self) == selectedTab {
view
.frame(maxWidth: .infinity, maxHeight: .infinity)
.transition(view[TabTransitionTrait.self])
}
}
}
.safeAreaInset(edge: .bottom) {
HStack {
Spacer()
ExtractMulti(content) { views in
ForEach(views) { view in
Group {
if let label = view[CustomTabItemTrait.self] {
label
} else {
Text("Unnamed")
}
}
.onTapGesture {
if let selection = view.id(as: Selection.self) {
selectedTab = selection
}
}
.foregroundStyle(
view.id(as: Selection.self) == selectedTab ?
AnyShapeStyle(Color.accentColor) : AnyShapeStyle(.opacity(1))
)
Spacer()
}
}
}
}
}
}
extension View {
func customTabItem<Content: View>(@ViewBuilder content: () -> Content) -> some View {
_trait(CustomTabItemTrait.self, AnyView(content()))
}
}
struct CustomTabItemTrait: _ViewTraitKey {
static let defaultValue: AnyView? = nil
}
extension View {
func tabTransition<T: Transition>(_ transition: T) -> some View {
_trait(TabTransitionTrait.self, AnyTransition(transition))
}
}
struct TabTransitionTrait: _ViewTraitKey {
static let defaultValue: AnyTransition = .identity
}
使用示例:
struct ContentView: View {
@State var selectedTab = 0
var body: some View {
CustomTabView(selectedTab: $selectedTab.animation()) {
Color.blue
.id(0) // you must use .id instead of .tag to specify the selection value
.customTabItem {
Label("Baz", systemImage: "circle")
}
.tabTransition(.push(from: .leading))
Color.yellow
.id(1)
.customTabItem {
Label("Foo", systemImage: "globe")
}
.tabTransition(.push(from: .bottom))
Color.green
.id(2)
.customTabItem {
Label("Bar", systemImage: "rectangle")
}
.tabTransition(.opacity)
}
}
}