繁体   English   中英

SwiftUI - 表单中的 NavigationLink 单元格在详细信息弹出后保持突出显示

[英]SwiftUI - NavigationLink cell in a Form stays highlighted after detail pop

在 iOS 14 中,看起来NavigationLink在返回Form上下文后不会被取消选择。 这也适用于Form Picker和其他任何导致从列表中显示另一个View的东西(为呈现单元格提供突出显示的上下文)。

我没有注意到 iOS 13 中的这种行为。

一旦另一个视图被关闭,有没有办法“取消选择”突出显示的行?

示例代码:

struct ContentView: View {

    var body: some View {
        Form {
            NavigationLink(destination: Text("Detail")) {
                Text("Link")
            } 
        }
    }

}

(不同)视觉示例:

例子

在我的情况下,这种行为出现在我的NavigationViewList/Form之间使用任何 Viewcontent(例如 Text()、Image()、...)时。

var body: some View {
    
    NavigationView {
        VStack {
            Text("This text DOES make problems.")
            List {
                NavigationLink(destination: Text("Doesn't work correct")) {
                    Text("Doesn't work correct")
                }
            }
        }
    }
}

将 Text()放在List之下不会产生任何问题:

var body: some View {
    
    NavigationView {
        VStack {
            List {
                NavigationLink(destination: Text("Does work correct")) {
                    Text("Does work correct")
                }
            }
            Text("This text doesn't make problems.")
        }
    }
}

这绝对是一个 XCode 12 错误。 随着越来越多的人报告这个问题,它会越早得到解决。

我也遇到了这个问题,并相信我找到了我的案例的根本原因。

在我的情况下,我有一个如下结构:

struct Page1View: View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Page 2", destination: Page2View())
            }
                .listStyle(GroupedListStyle())
                .navigationBarTitle("Page 1")
        }
    }
}

struct Page2View: View {
    var body: some View {
        List {
            NavigationLink("Page 3", destination: Text("Page 3"))
        }
            .listStyle(GroupedListStyle())
            .navigationBarTitle("Page 2")
    }
}

此问题会发生在 NavigationLink 到页面 3 上。在控制台输出中,使用该链接时会显示此错误:

2021-02-13 16:41:00.599844+0000 App[59157:254215] [Assert] displayModeButtonItem is internally managed and not exposed for DoubleColumn style. Returning an empty, disconnected UIBarButtonItem to fulfill the non-null contract.

我发现我需要将.navigationViewStyle(StackNavigationViewStyle())应用于 NavigationView,这解决了问题。

IE

struct Page1View: View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Page 2", destination: Page2View())
            }
                .listStyle(GroupedListStyle())
                .navigationBarTitle("Page 1")
        }
            .navigationViewStyle(StackNavigationViewStyle())
    }
}

今天一直在与这个问题作斗争半天,来到这篇文章,帮助我理解如果TextButton或其他东西放在NavigationView和我的案例List之间会出现这个问题。 我找到了对我有用的解决方案。 只需为该项目添加.zIndex() .zIndex()必须高于List Tried with Xcode 12.5

var body: some View {
    NavigationView {
        VStack {
            Text("This text DOES make problems.")
                .zIndex(1.0)
            List {
                NavigationLink(destination: Text("Doesn't work correct")) {
                    Text("Doesn't work correct")
                }
            }
        }
    }
}

我做了一些修补,结果证明这是由于UIHostingController嵌套在UINavigationController并使用该导航控制器造成的。 更改导航堆栈以使用 SwiftUI NavigationView解决了此问题。

与@pawello2222 在问题评论中所说的类似,我认为根本原因与 SwiftUI 在使用外部UINavigationController时不理解正确的导航层次结构有关。

这只是修复了此问题的一个实例,根据我的视图结构,我仍在各种其他上下文中遇到此问题。

我已经向 Apple 提交了一份问题报告FB8705430 ,所以希望这个问题很快得到解决。

之前(损坏):

struct ContentView: View {
    var body: some View {
        Form {
             NavigationLink(destination: Text("test")) {
                 Text("test")
             }
        }
    }
}

// (UIKit presentation context)
let view = ContentView() 
let host = UIHostingController(rootView: view)
let nav = UINavigationController(rootViewController: host)
present(nav, animated: true, completion: nil)

之后(工作):

struct ContentView: View {
    var body: some View {
        NavigationView {
            Form {
                NavigationLink(destination: Text("test")) {
                    Text("test")
                }
            }
        }
    }
}

// (UIKit presentation context)
let view = ContentView()
let host = UIHostingController(rootView: view)
present(host, animated: true, completion: nil)

这绝对是List一个错误,目前,我的解决方法是通过更改 id 来刷新List ,如下所示:

struct YourView: View {
    @State private var selectedItem: String?
    @State private var listViewId = UUID()

    var body: some View {
            List(items, id: \.id) {
                NavigationLink(destination: Text($0.id), 
                               tag: $0.id, 
                               selection: $selectedItem) {
                  Text("Row \($0.id)")
                }
            }
            .id(listViewId)
            .onAppear {
                if selectedItem != nil {
                    selectedItem = nil
                    listViewId = UUID()
                }
            }
    } 
}

我基于此制作了一个修饰符,您可以使用:

struct RefreshOnAppearModifier<Tag: Hashable>: ViewModifier {
    @State private var viewId = UUID()
    @Binding var selection: Tag?
    
    func body(content: Content) -> some View {
        content
            .id(viewId)
            .onAppear {
                if selection != nil {
                    viewId = UUID()
                    selection = nil
                }
            }
    }
}

extension View {
    func refreshOnAppear<Tag: Hashable>(selection: Binding<Tag?>? = nil) -> some View {
        modifier(RefreshOnAppearModifier(selection: selection ?? .constant(nil)))
    }
}

像这样使用它:

List { ... }
  .refreshOnAppear(selection: $selectedItem)

我设法通过向列表的不同组件添加 id,使用绑定并重置 .onDisappear 上的绑定来解决它

struct ContentView: View {
    @State var selection: String? = nil

    var body: some View {
        NavigationView {
            VStack {
                Text("Hello, world!")
                    .padding()
                List {
                    Section {
                        NavigationLink( destination: Text("Subscreen1"), tag: "link1", selection: $selection ) {
                            Text("Subscreen1")
                        }.onDisappear {
                            self.selection = nil
                        }
                        NavigationLink( destination: Text("Subscreen2"), tag: "link2", selection: $selection ) {
                            Text("Subscreen2")
                        }.onDisappear {
                            self.selection = nil
                        }
                    }.id("idSection1")
                }
                .id("idList")
            }
        }
    }
}

我也遇到过这个问题,它似乎与这里提到的工作表有关。

我的解决方案是调整UITableView捕捉选择,并取消选择单元格。 这样做的代码在这里 希望这将在未来的 iOS 中得到修复。

这是我一直在使用的解决方法,直到此 List 问题得到修复。 使用Introspect库,我保存 List 的 UITableView.reloadData 方法并在它再次出现时调用它。

import SwiftUI
import Introspect

struct MyView: View {

    @State var reload: (() -> Void)? = nil

    var body: some View {
        NavigationView {
            List {
                NavigationLink("Next", destination: Text("Hello"))
            }.introspectTableView { tv in
                self.reload = tv.reloadData
            }.onAppear {
                self.reload?()
            }
        }
    }
}

.navigationViewStyle(StackNavigationViewStyle())添加到NavigationView为我修复了它。

在此线程中建议: https : //developer.apple.com/forums/thread/660468

这是我对这个问题的解决方案。

// This in a stack in front of list, disables large navigation title from collapsing by disallowing list from scrolling on top of navigation title
public struct PreventCollapseView: View { 

    @State public var viewColor: Color?

    public init(color: Color? = nil) {
        self.viewColor = color
    }
    
    public var body: some View {
        Rectangle()
            .fill(viewColor ?? Color(UIColor(white: 0.0, alpha: 0.0005)))
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 1)
    }
}

// handy modifier..
extension List {
    
    public func uncollapsing(_ viewUpdater: Bool) -> some View {
        
        VStack(spacing: 0.0) {
            Group {
                PreventCollapseView()
                self
            }.id(viewUpdater)
        }
    }
}

struct TestView: View {

    @State var updater: Bool = false
    
    var body: some View {

        List {
            Text("Item one")
            Text("Item two")
            Text("Manually refresh")
                .onTapGesture { DispatchQueue.main.async { updater.toggle() } }
                .onAppear { print("List was refreshed") }
        }
        .uncollapsing(updater)
        .clipped()
        .onAppear { DispatchQueue.main.async { updater.toggle() }} // Manually refreshes list always when re-appearing/appearing

    }
}

添加 NavigationView,为 largeTitle 配置,并嵌入 TestView,一切就绪。 切换更新程序以刷新。

有同样的问题。 奇怪的是,完全相同的代码在 iOS13 中工作。 我在一个简单的列表中遇到了这个问题:

struct TestList: View {
    let someArray = ["one", "two", "three", "four", "five"] 
    var body: some View {
        List(someArray, id: \.self) { item in 
                NavigationLink(
                    destination: Text(item)) {
                    Text(item)
                }.buttonStyle(PlainButtonStyle()) 
        }.navigationBarTitle("testlist") 
    }
}

这嵌入在:

struct ListControllerView: View {
    @State private var listPicker = 0
    var body: some View {
        NavigationView{
            Group{
                VStack{
                    Picker(selection: $listPicker, label: Text("Detailoverview")) {
                        Text("foo").tag(0)
                        Text("bar").tag(1)
                        Text("TestList").tag(2)
                    }

这是在 Tabbar 内。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM