繁体   English   中英

SwiftUI 列表按钮,带披露指示灯

[英]SwiftUI List Button with Disclosure Indicator

我有一个 SwiftUI 视图,其中包含一个包含一些项目的列表。 其中一些是指向其他屏幕的链接(因此我使用NavigationLink来执行此操作),而另一些是我想在当前屏幕上执行的操作(例如,显示操作表的按钮)。

我正在为 SwiftUI List中的Button寻找一种方法,以显示带有披露指示器(为NavigationLink显示的右侧标志处的 V 形)。

这可能吗?

例如

struct ExampleView: View {
    @State private var showingActionSheet = false
    
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Navigation Link", destination: Text("xx"))
                Button("Action Sheet") {
                    self.showingActionSheet = true
                }
                .foregroundColor(.black)
            }
            .listStyle(GroupedListStyle())
            .actionSheet(isPresented: $showingActionSheet) {
                ActionSheet(title: Text("Title"), buttons: [
                    .default(Text("Do Something")) {  },
                    .cancel()
                ])
            }
        }
    }
}

当前行为:

当前行为

想要的行为:

通缉行为

我的回答使用SwiftUI-Introspect框架,用于:

内省来自 SwiftUI 的底层 UIKit 组件

在这种情况下,它用于在按下NavigationLink后取消选择行。

我认为具有正常强调色且没有 NavigationLink 的按钮对用户来说更直观,但如果这是您需要的,就在这里。 以下答案应该适合您:

import Introspect
import SwiftUI


struct ExampleView: View {
    
    @State private var showingActionSheet = false
    @State private var tableView: UITableView?
    
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Navigation Link", destination: Text("xx"))
                
                NavigationLink(
                    destination: EmptyView(),
                    isActive: Binding<Bool>(
                        get: { false },
                        set: { _ in
                            showingActionSheet = true
                            
                            DispatchQueue.main.async {
                                deselectRows()
                            }
                        }
                    )
                ) {
                    Text("Action Sheet")
                }
            }
            .introspectTableView { tableView = $0 }
            .listStyle(GroupedListStyle())
            .actionSheet(isPresented: $showingActionSheet) {
                ActionSheet(title: Text("Title"), buttons: [
                    .default(Text("Do Something")) {  },
                    .cancel()
                ])
            }
        }
    }
    
    private func deselectRows() {
        if let tableView = tableView, let selectedRow = tableView.indexPathForSelectedRow {
            tableView.deselectRow(at: selectedRow, animated: true)
        }
    }
}

可能的方法是使用自定义 chevron 进行排列,如下面的演示所示(使用 Xcode 12.1 / iOS 14.1 测试)

演示

struct ExampleView: View {
    @State private var showingActionSheet = false
    
    var body: some View {
        NavigationView {
            List {
                HStack {
                    Text("Navigation Link")

                    // need to hide navigation link to use same chevrons
                    // because default one is different
                    NavigationLink(destination: Text("xx")) { EmptyView() }
                    Image(systemName: "chevron.right")
                        .foregroundColor(Color.gray)
                }
                HStack {
                    Button("Action Sheet") {
                        self.showingActionSheet = true
                    }
                    .foregroundColor(.black)
                    Spacer()
                    Image(systemName: "chevron.right")
                        .foregroundColor(Color.gray)
                }
            }
            .listStyle(GroupedListStyle())
            .actionSheet(isPresented: $showingActionSheet) {
                ActionSheet(title: Text("Title"), buttons: [
                    .default(Text("Do Something")) {  },
                    .cancel()
                ])
            }
        }
    }
}

我使用 ZStack 将带有空 label 的NavigationLink放在实际 label 内容后面。 这样你就得到了正确的人字形符号。 对于isActive绑定,您可以只使用.constant(false)绑定,该绑定将始终返回 false 并且无法更改。

这将产生一个看起来与 NavigationLink 完全一样的行,但其行为类似于 Button。 不幸的是,这还包括用户必须单击标签内容(文本)才能激活按钮并且不能只单击单元格的空白区域的缺点。

截屏

struct ExampleView: View {
    @State private var showingActionSheet = false
    
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Navigation Link", destination: Text("xx"))
                Button {
                    self.showingActionSheet = true
                } label: {
                    // Put a NavigationLink behind the actual label for the chevron
                    ZStack(alignment: .leading) {
                        // NavigationLink that can never be activated
                        NavigationLink(
                            isActive: .constant(false),
                            destination: { EmptyView() },
                            label: { EmptyView() }
                        )
                        // Actual label content
                        Text("Action Sheet")
                    }
                }
                // Prevent the blue button tint
                .buttonStyle(.plain)
            }
            .listStyle(GroupedListStyle())
            .actionSheet(isPresented: $showingActionSheet) {
                ActionSheet(title: Text("Title"), buttons: [
                    .default(Text("Do Something")) {  },
                    .cancel()
                ])
            }
        }
    }
}
struct NavigationButton: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        ZStack(alignment: .leading) {
            NavigationLink(
                isActive: .constant(false),
                destination: { EmptyView() },
                label: { EmptyView() }
            )
            configuration.label
        }
    }
}

例子:

NavigationView {
            List {
                
                Button(action: {
                    openURL(URL(string: "https://www.apple.com")!)
                }) {
                    Text("Visit Apple")
                }
                .buttonStyle(NavigationButton())
                
            }
}

暂无
暂无

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

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