SwiftUI onReceive 是否可以获取oldValue?

标签 swiftui tabview didset

我有一个自定义 TabView,我想绑定(bind)到一个状态来更改选项卡。我还想检测用户是否再次点击相同的选项卡以滚动到该 View 的顶部。

当我使用绑定(bind)时,不会调用 didSet。 onChange 没有被调用,因为值没有改变,并且 onReceive 没有给我旧的值来比较。

有什么想法吗? (尽量避免使用已发布的属性)

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)
            }
            .onReceive(Just(selectedTab)) { [oldValue = selectedTab] newValue in
                print("Old: \(oldValue)") //Shows newValue
                print("New: \(newValue)")
                if oldValue == newValue {
                    switch selectedTab {
                    case 1:
                        scrollToTop1.toggle()
                    case 2:
                        scrollToTop2.toggle()
                    default:
                        break
                    }
                }
            }
            
            TabBar(selectedTab: $selectedTab)
        }
    }
}

struct TabBar: View {
    @Binding var selectedTab: Int
    
    var body: some View {
        HStack {
            TabItem(selectedTab: $selectedTab, text: "View 1", tab: 1)
            TabItem(selectedTab: $selectedTab, text: "View 2", tab: 2)
        }
        .background(Color.green)
    }
}

struct TabItem: View {
    @Binding var selectedTab: Int
    let text: String
    let tab: Int
    
    var body: some View {
        Button {
            selectedTab = tab
        } label: {
            Text(text)
        }
        .frame(maxWidth: .infinity)
        .frame(height: 50)
    }
}

最佳答案

我认为这是自定义绑定(bind)的一个很好的场景,您可以在设置之前拦截该值并进行比较:

struct ContentView: View {
    
    @State private var scrollToTop1: Bool = false
    @State private var scrollToTop2: Bool = false
    
    @State private var selectedTab: Int = 1
    
    var customBinding: Binding<Int> {
        .init {
            selectedTab
        } set: { newValue in
            print("New value: ", newValue)
            if newValue == selectedTab {
                print("Scroll to top")
            }
            selectedTab = newValue
        }
    }
    
    var body: some View {
        ZStack(alignment: .bottom) {
            TabView(selection: customBinding) {
                NavigationView {
                    Text("1")
                }
                .tag(1)
                
                NavigationView {
                    Text("2")
                }
                .tag(2)
            }
            
            TabBar(selectedTab: customBinding)
        }
    }
}

struct TabBar: View {
    @Binding var selectedTab: Int
    
    var body: some View {
        HStack {
            TabItem(selectedTab: $selectedTab, text: "View 1", tab: 1)
            TabItem(selectedTab: $selectedTab, text: "View 2", tab: 2)
        }
        .background(Color.green)
    }
}

关于SwiftUI onReceive 是否可以获取oldValue?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74732777/

相关文章:

SwiftUI 分段选取器在单击时不会切换

objective-c - 如何设置 NSTabView 的背景颜色?

ios - 在启动时以编程方式为 5 个选项卡栏项目设置选项卡栏标题,其中 4 个嵌入在导航 Controller 中,1 个不是。 objective-c

Swift - didSet 中的弱 self

swift - 有没有办法从对象本身调用对象的 "didSet"?

Swift willSet/didSet 赋值?

swift - 在 SwiftUI View 中设置计算属性无法编译

ios - SwiftUI - 预览 Canvas 出现协调安装错误

swift - 在 ScrollView 中居中并对齐 SwiftUI 元素

swift - 更改默认蓝色 TabBar