向后滑动失败时,SwiftUI 导航栏项目变得混乱

Posted

技术标签:

【中文标题】向后滑动失败时,SwiftUI 导航栏项目变得混乱【英文标题】:SwiftUI navigation bar items going haywire when swipe back fails 【发布时间】:2020-09-16 21:30:39 【问题描述】:

我有一个ListViewTasksView,然后是EditView

流程是这样的:你有一个列表单元格,你点击它会将你带到TasksView 当在TasksView 中点击一行时,它会将你带到EditView

当我向后滑动一半以导航到上一个视图时,导航栏会变得笨拙并重叠。它主要发生在我使用navigationBarItem - (按钮)时。

TasksView (detailView) 中有一个列表和一些导航栏修饰符:

ZStack 
   List 
    // code here
 


.onAppear  UITableView.appearance().separatorStyle = .none 
.onDisappear  UITableView.appearance().separatorStyle = .none 
.background(Color("primaryBackground"))
.edgesIgnoringSafeArea(.bottom)
.navigationBarTitle("\(listItem.name ?? "")", displayMode: .inline)
.navigationBarItems(trailing:
    Button(action: self.deleteList()) 
              Image(systemName: "trash.circle.fill")
          
     )

EditView 也是如此,当您在EditView 上滑动一半以返回TasksView 时,也会发生同样的事情。

以下是实际中的错误:

有人知道如何解决这个错误吗?

编辑:

struct TasksView: View 
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var taskControl: TaskControl
@EnvironmentObject var addNewTaskData: AddNewTaskViewDataFlow
@ObservedObject var dataPickerData : DatePickerDataFlowV2


@FetchRequest(entity: ONList.entity(), sortDescriptors: []) var listsDataSource: FetchedResults<ONList>
@Environment(\.managedObjectContext) var listMOC

   var listItem: ONList
   var keyboardPublisher: AnyCancellable

 // defining the presentationMode here 

 .......

ZStack 
        NavigationLink(destination: ListOptions(listItem: listItem), tag: 1, selection: self.$navigationSelectionTag) 
            EmptyView()
        

        Color("primaryBackground")
            .edgesIgnoringSafeArea(.top)

        //... more code here
      

    .onAppear 

        UITableView.appearance().separatorStyle = .none
        self.taskControl.taskViewerSeperator = true
    
    .onDisappear 
        UITableView.appearance().separatorStyle = .none
        print("Bye Task View")

        if UIDevice.current.userInterfaceIdiom == .phone 
          self.taskControl.taskViewerSeperator = false
        

        self.keyboardPublisher.cancel()
    
    .navigationBarTitle("\(listItem.name ?? "")", displayMode: .inline)
    .background(Color("primaryBackground"))
    .edgesIgnoringSafeArea(.bottom)
    .navigationBarItems(trailing:
        HStack 
        Button(action: 
        self.navigationSelectionTag = 1
    , label: 
        Image(systemName: "gear")
    )

       Button(action: 
        self.deleteList()

       ) 
          Image(systemName: "trash.circle.fill")

    .padding()

    
  )

我什至没有在deleteList() 函数中使用presentationMode,以便在删除当前视图时将其关闭。但是,我仍然遇到与上面 gif 中所示相同的故障。

更新:

struct TestingCoreData: View 

var body: some View 
    NavigationView 
        VStack 
            NavigationLink(destination: DestinationView()) 
                 Text("This is a test")
            


        .navigationBarTitle(Text("Master"), displayMode: .inline)
         .navigationBarItems(trailing:
            Button(action: 
                print("tapped")
            ) 
                Text("Button")
            

        )
    



struct DestinationView: View 

@Environment(\.presentationMode) var presentationMode
var body: some View 

List 
    Text("DestinationView")
        .padding(.top, 100)
        .navigationBarTitle(Text("Destination"), displayMode: .inline)
        .navigationBarItems(trailing: Button(action: 
            self.presentationMode.wrappedValue.dismiss()
        , label: 
            Text("second")
        ))




上面的代码重现了这个错误。当你点击“这是一个测试”按钮,然后你往回滑动一点,然后回到上一个视图,你会看到导航栏变得乱七八糟!

【问题讨论】:

How to create a Minimal, Reproducible Example 【参考方案1】:

我找到了一个简单的解决方案来解决您的问题,将其添加到 NavigationView

    NavigationView 
        ....
    .navigationViewStyle(StackNavigationViewStyle())

编辑:这是我用来在真实设备和各种模拟器上测试我的答案的代码。这解决了问题,如果您发现无法使用此功能的设备,请告诉我。

import SwiftUI

struct ContentView: View 
var body: some View 
    NavigationView 
        VStack 
            NavigationLink(destination: DestinationView()) 
                Text("This is a test")
            
        .navigationBarTitle(Text("Master"), displayMode: .inline)
            .navigationBarItems(trailing:
                Button(action: 
                    print("tapped")
                ) 
                    Text("Button")
            )
    .navigationViewStyle(StackNavigationViewStyle())



struct DestinationView: View 
@Environment(\.presentationMode) var presentationMode
var body: some View 
    List 
        Text("DestinationView")
            .padding(.top, 100)
            .navigationBarTitle(Text("Destination"), displayMode: .inline)
            .navigationBarItems(trailing: Button(action: 
                self.presentationMode.wrappedValue.dismiss()
            , label: 
                Text("second")
            ))
    

 

【讨论】:

这并不能解决问题。 我已更新我的答案以准确显示我正在使用的代码。我已经在真实设备和各种模拟器上对此进行了测试,没有任何问题。您能否告诉我们此代码在哪些设备/系统上不适合您。我在 mac 10.15 上使用了 Xcode 11.5 和 11.6 beta,目标是 ios 13.5 和 mac 催化剂。 这将如何转化为 iPad 版本?使用 StackNavigationViewStyle,您实际上是在移除 iPad 的主细节视图布局。 我在 iPad 上测试过,不管有没有我的添加,它都能很好地工作。您有解决方案不起作用的设备吗?【参考方案2】:

我曾在同样的问题上苦苦挣扎。所以我决定制作一个带有视图修饰符的自定义导航栏,我正在使用它。 但我想我现在找到了另一种解决方案。 尝试在NavigationLink 之后添加.isDetailLink(false)

NavigationLink(destination: DestinationView()) 
    Text("This is a test")

.isDetailLink(false)

【讨论】:

【参考方案3】:

使用 .toolbarToolbarItem 而不是旧的 .navigationBarItems 可以解决问题。

还请注意,我已将导航修饰符从 Text 移至 List

这是一个基于您的 UPDATE 代码的有效且经过测试的示例:

import SwiftUI

struct ContentView: View 
    
    var body: some View 
        NavigationView 
            VStack 
                NavigationLink(destination: DestinationView()) 
                    Text("This is a test")
                
            
            .navigationBarTitle(Text("Master"), displayMode: .inline)
            
            // use .toolbar instead of .navigationBarItems
            .toolbar 
                ToolbarItem(placement: .navigationBarTrailing)
                    Button("Button", action: 
                        print("tapped")
                    )
                
            
            
        
    


struct DestinationView: View 
    
    @Environment(\.presentationMode) var presentationMode
    var body: some View 
        
        List 
            Text("DestinationView")
                .padding(.top, 100)
        
        .navigationBarTitle(Text("Destination"), displayMode: .inline)
        // use .toolbar instead of .navigationBarItems
        .toolbar 
            ToolbarItem(placement: .navigationBarTrailing)
                Button("second", action: 
                    self.presentationMode.wrappedValue.dismiss()
                )
            
        
        
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    

【讨论】:

以上是关于向后滑动失败时,SwiftUI 导航栏项目变得混乱的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中滑动列表时隐藏导航栏

如果同时触发滑动手势和后退按钮,导航栏会变得很时髦

向后滑动时嵌套推送动画可能导致导航栏损坏

SwiftUI - navigationBarBackButtonHidden - 向后滑动手势?

在 UINavigationController 中隐藏导航栏时不向后滑动

滑动回根视图控制器时,大型导航栏背景颜色变得清晰