SwiftUI:检测点击已选择的列表项

SwiftUI: Detect click on already selected list item

我有一个包含多个项目的 List 视图。所有这些都用于导航目的,并且都是 Text。我不能为这个应用程序使用NavigationLink

也就是说,我正在通过 @State 变量监视列表 selection。

@State private var selection: String?

只要视图更新,我就会打印它的值。当 selecting 列表中的不同 项时,它通常会打印每个项的唯一性 id

问题是在尝试 select 再次 相同的项目时 :在这种情况下,视图没有更新,我也没有看到调试消息在我的控制台中。

我希望能够按下列表项以显示视图,然后能够再次按下它,尽管它已经被 selected 因为我有逻辑我想运行(例如:手动视图刷新)。

如何检测已 select 已编辑列表项的重新select离子?

如有任何问题,请告诉我。感谢您的帮助!


更新 1

这是我使用的代码:
帮助列表项结构:

struct NavItem {
    let id: String
    let text: String
}

列表:

struct NavList: View {
    
    @Binding private var selection: String?
    private var listItems: [NavItem]
    
    //note:
    //selection is a @State variable declared in a parent struct and passed here.
    //This is optional. I could declare it as a @state too.
    init(listItems: [NavItem], selection: Binding<String?>) { 
        self.listItems = listItems
        self._selection = selection
        debugPrint(self.selection)
    }
    
    var body: some View {
        
        List (selection: $selection) {
            ForEach(listItems, id:\.id) { item in 
                Text(item.text)
                    .tag(item.id)
            }
        }
    }
}

注1:我已经知道这个问题可以通过使用.onTapGesture修饰符来解决。这个解决方案似乎不是最优的。我试着寻求帮助 here.

注2:在项目中,包含列表的struct符合View。当显示该视图时,它添加了 .listStyle(SidebarListStyle()) 修饰符。这可能是相关的。

有很多方法可以做你想做的事, 用 .onTapGesture{..}

试试这个
    List (selection: $selection) {
        ForEach(listItems, id: \.id) { item in
            Text(item.text)
                .tag(item.id)
                .padding(10)
                .listRowInsets(.init(top: 0,leading: 0, bottom: 0, trailing: 0))
                .frame(minWidth: 111, idealWidth: .infinity, maxWidth: .infinity, alignment: .leading)
                .onTapGesture {
                    print("----> " + item.text)
                }
        }
    }
    

或者您可以使用 Button 而不是 onTapGesture

    List (selection: $selection) {
        ForEach(listItems, id: \.id) { item in
            Button(action: { print("----> " + item.text) }) {
                Text(item.text)
            }
                .padding(10)
                .listRowInsets(.init(top: 0,leading: 0, bottom: 0, trailing: 0))
            .tag(item.id)
            .frame(minWidth: 111, idealWidth: .infinity, maxWidth: .infinity, alignment: .leading)
        }
    }

编辑:完整测试代码:

这是我在测试中使用的代码:

import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
    }
}

struct NavItem {
    let id: String
    let text: String
}

struct ContentView: View {
    @State private var listItems: [NavItem] = [NavItem(id: "1", text: "1"),
                                              NavItem(id: "2", text: "2"),
                                              NavItem(id: "3", text: "3"),
                                              NavItem(id: "4", text: "4")]
    @State private var selection: String?
    
    var body: some View {
        List (selection: $selection) {
            ForEach(listItems, id:\.id) { item in
                Button(action: { print("----> " + item.text) }) {
                    Text(item.text)
                }
                .padding(10)
                .listRowInsets(.init(top: 0,leading: -5, bottom: 0, trailing: -5))
                .frame(minWidth: 111, idealWidth: .infinity, maxWidth: .infinity, alignment: .leading)
                .tag(item.id)
                .background(Color.red)  // <--- last modifier
            }
        }
    }
 }