SwiftUI中onReceive能否获取oldValue?同Tab点击返回顶部实现
解决方案:捕获TabItem重复点击实现滚动到顶部
问题根源在于:点击当前选中的TabItem时,selectedTab的值没有变化,依赖值变化的didSet、onChange、onReceive都无法触发。核心解决思路是直接在点击事件触发时判断是否是当前标签,而非等待值变化。
步骤1:重构TabItem,用闭包传递点击动作
移除@Binding var selectedTab,改用闭包action让父视图控制点击行为:
struct TabItem: View { let text: String let action: () -> Void var body: some View { Button(action: action) { Text(text) } .frame(maxWidth: .infinity) .frame(height: 50) } }
步骤2:修改TabBar,传递选中状态和点击回调
让TabBar接收当前选中标签值,以及点击后的回调逻辑:
struct TabBar: View { let selectedTab: Int let onTabTap: (Int) -> Void var body: some View { HStack { TabItem(text: "View 1") { onTabTap(1) } TabItem(text: "View 2") { onTabTap(2) } } .background(Color.green) } }
步骤3:在ContentView中处理点击逻辑
在TabBar的回调里判断点击标签是否为当前选中项:是则触发滚动到顶部,否则切换标签:
struct ContentView: View { @State private var scrollToTop1: Bool = false @State private var scrollToTop2: Bool = false @State private var selectedTab: Int = 1 var body: some View { ZStack(alignment: .bottom) { TabView(selection: $selectedTab) { NavigationView { View1(scrollToTop: $scrollToTop1) } .tag(1) NavigationView { View2(scrollToTop: $scrollToTop2) } .tag(2) } TabBar(selectedTab: selectedTab, onTabTap: { tab in if tab == selectedTab { // 重复点击当前标签,触发滚动到顶部 switch tab { case 1: scrollToTop1.toggle() case 2: scrollToTop2.toggle() default: break } } else { // 切换标签 selectedTab = tab } }) } } }
补充说明
- 该方案无需依赖
@Published或值变化监听,直接在点击事件源头处理逻辑,彻底规避了值未变化时无法触发回调的问题。 View1和View2只需监听scrollToTop的变化,配合ScrollViewReader的scrollTo方法即可完成滚动到顶部的操作。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

