You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NavigationSplitView侧边栏切换列表后推送动画失效问题咨询

问题:NavigationSplitView在iPhone切换列表后首次选择无推送动画

在NavigationSplitView中实现了通过工具栏Picker切换两类列表的侧边栏,切换数据后首次选择列表项时,iPhone上无法显示推送动画,但iPad端运行正常。

以下是原代码:

import SwiftUI

struct ContentView: View {
  @State private var tab: PickerTab = .fruits
  @State private var selectedFruit: Fruit?
  @State private var selectedVegetable: Vegetable?
  
  private var fruits: [Fruit] = [
    Fruit(name: "Strawberry", color: .red),
    Fruit(name: "Blueberry", color: .blue)
  ]
  
  private var vegetables: [Vegetable] = [
    Vegetable(name: "Carrot", color: .orange),
    Vegetable(name: "Broccoli", color: .green)
  ]
  
  var body: some View {
    NavigationSplitView {
      Group {
        switch tab {
        case .fruits:
          List(fruits, selection: $selectedFruit) { fruit in
            NavigationLink(value: fruit) {
              Text(fruit.name)
            }
          }
        case .vegetables:
          List(vegetables, selection: $selectedVegetable) { vegetable in
            NavigationLink(value: vegetable) {
              Text(vegetable.name)
            }
          }
        }
      }
      .toolbar {
        ToolbarItem(placement: .principal) {
          Picker("Sidebar", selection: $tab) {
            ForEach(PickerTab.allCases, id: \.self) { tab in
              Text(tab.rawValue.capitalized)
            }
          }
          .pickerStyle(.segmented)
        }
      }
    } detail: {
      switch tab {
      case .fruits:
        if let selectedFruit {
          Text(selectedFruit.name)
            .foregroundStyle(selectedFruit.color)
        }
      case .vegetables:
        if let selectedVegetable {
          Text(selectedVegetable.name)
            .foregroundStyle(selectedVegetable.color)
        }
      }
    }
  }
}

enum PickerTab: String, Hashable, CaseIterable {
  case fruits
  case vegetables
}

struct Fruit: Hashable, Identifiable {
  let id = UUID()
  let name: String
  let color: Color
}

struct Vegetable: Hashable, Identifiable {
  let id = UUID()
  let name: String
  let color: Color
}

问题原因

切换Picker时,未重置另一类列表的选中状态变量(如切换到水果列表时,蔬菜的selectedVegetable仍保留之前的值),导致NavigationSplitView在iPhone折叠模式下无法正确识别状态变化,从而跳过推送动画。

解决方案

方案1:切换tab时重置未激活类别的选中状态

添加onChange监听tab切换事件,将未使用的选中状态置为nil,确保状态同步:

import SwiftUI

struct ContentView: View {
    @State private var tab: PickerTab = .fruits
    @State private var selectedFruit: Fruit?
    @State private var selectedVegetable: Vegetable?
    
    private var fruits: [Fruit] = [
        Fruit(name: "Strawberry", color: .red),
        Fruit(name: "Blueberry", color: .blue)
    ]
    
    private var vegetables: [Vegetable] = [
        Vegetable(name: "Carrot", color: .orange),
        Vegetable(name: "Broccoli", color: .green)
    ]
    
    var body: some View {
        NavigationSplitView {
            Group {
                switch tab {
                case .fruits:
                    List(fruits, selection: $selectedFruit) { fruit in
                        NavigationLink(value: fruit) {
                            Text(fruit.name)
                        }
                    }
                case .vegetables:
                    List(vegetables, selection: $selectedVegetable) { vegetable in
                        NavigationLink(value: vegetable) {
                            Text(vegetable.name)
                        }
                    }
                }
            }
            .toolbar {
                ToolbarItem(placement: .principal) {
                    Picker("Sidebar", selection: $tab) {
                        ForEach(PickerTab.allCases, id: \.self) { tab in
                            Text(tab.rawValue.capitalized)
                        }
                    }
                    .pickerStyle(.segmented)
                }
            }
            // 关键:切换tab时重置另一类选中状态
            .onChange(of: tab) { newTab in
                if newTab == .fruits {
                    selectedVegetable = nil
                } else {
                    selectedFruit = nil
                }
            }
        } detail: {
            switch tab {
            case .fruits:
                if let selectedFruit {
                    Text(selectedFruit.name)
                        .foregroundStyle(selectedFruit.color)
                } else {
                    Text("Select a fruit")
                }
            case .vegetables:
                if let selectedVegetable {
                    Text(selectedVegetable.name)
                        .foregroundStyle(selectedVegetable.color)
                } else {
                    Text("Select a vegetable")
                }
            }
        }
    }
}

// 枚举和模型定义保持不变
enum PickerTab: String, Hashable, CaseIterable {
    case fruits
    case vegetables
}

struct Fruit: Hashable, Identifiable {
    let id = UUID()
    let name: String
    let color: Color
}

struct Vegetable: Hashable, Identifiable {
    let id = UUID()
    let name: String
    let color: Color
}

方案2:统一管理选中状态变量

用一个AnyHashable类型的变量存储选中项,避免维护多个状态变量,状态同步更简洁:

import SwiftUI

struct ContentView: View {
    @State private var tab: PickerTab = .fruits
    @State private var selectedItem: AnyHashable? // 统一管理选中项
    
    private var fruits: [Fruit] = [
        Fruit(name: "Strawberry", color: .red),
        Fruit(name: "Blueberry", color: .blue)
    ]
    
    private var vegetables: [Vegetable] = [
        Vegetable(name: "Carrot", color: .orange),
        Vegetable(name: "Broccoli", color: .green)
    ]
    
    var body: some View {
        NavigationSplitView {
            Group {
                switch tab {
                case .fruits:
                    List(fruits, selection: $selectedItem) { fruit in
                        NavigationLink(value: fruit) {
                            Text(fruit.name)
                        }
                    }
                case .vegetables:
                    List(vegetables, selection: $selectedItem) { vegetable in
                        NavigationLink(value: vegetable) {
                            Text(vegetable.name)
                        }
                    }
                }
            }
            .toolbar {
                ToolbarItem(placement: .principal) {
                    Picker("Sidebar", selection: $tab) {
                        ForEach(PickerTab.allCases, id: \.self) { tab in
                            Text(tab.rawValue.capitalized)
                        }
                    }
                    .pickerStyle(.segmented)
                }
            }
        } detail: {
            switch tab {
            case .fruits:
                if let fruit = selectedItem as? Fruit {
                    Text(fruit.name)
                        .foregroundStyle(fruit.color)
                } else {
                    Text("Select a fruit")
                }
            case .vegetables:
                if let vegetable = selectedItem as? Vegetable {
                    Text(vegetable.name)
                        .foregroundStyle(vegetable.color)
                } else {
                    Text("Select a vegetable")
                }
            }
        }
    }
}

// 枚举和模型定义保持不变
enum PickerTab: String, Hashable, CaseIterable {
    case fruits
    case vegetables
}

struct Fruit: Hashable, Identifiable {
    let id = UUID()
    let name: String
    let color: Color
}

struct Vegetable: Hashable, Identifiable {
    let id = UUID()
    let name: String
    let color: Color
}

两种方案都能解决iPhone上的动画问题,方案2更简洁,减少状态维护成本。

内容的提问来源于stack exchange,提问作者rizz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 15:18:11