带有披露指示器的 SwiftUI 列表按钮
SwiftUI List Button with Disclosure Indicator
我有一个 SwiftUI 视图,它包含一个包含一些项目的列表。其中一些是指向其他屏幕的链接(因此我使用 NavigationLink
来执行此操作),其他一些是我想在当前屏幕上执行的操作(例如显示操作的按钮 sheet)。
我正在寻找一种方法,让 SwiftUI List
中的 Button
显示披露指示符(NavigationLink
右侧标志处的人字形) .
这可能吗?
例如
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框架,用于:
Introspect underlying UIKit components from SwiftUI
在这种情况下,它用于取消选择按下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 = [=10=] }
.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)
}
}
}
可能的方法是使用自定义人字形制作行,如下面的演示(使用 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 在实际标签内容后面放置了一个带有空标签的 NavigationLink
。这样您就可以获得正确的人字形符号。
对于 isActive
绑定,您可以只使用 .constant(false)
绑定,该绑定始终 return false 且无法更改。
这将生成一个看起来与 NavigationLink 完全一样的行,但其行为却与 Button 类似。不幸的是,这还包括用户必须单击 label-content(文本)才能激活按钮的缺点,而不能只单击单元格的空 space。
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()
])
}
}
}
}
我有一个 SwiftUI 视图,它包含一个包含一些项目的列表。其中一些是指向其他屏幕的链接(因此我使用 NavigationLink
来执行此操作),其他一些是我想在当前屏幕上执行的操作(例如显示操作的按钮 sheet)。
我正在寻找一种方法,让 SwiftUI List
中的 Button
显示披露指示符(NavigationLink
右侧标志处的人字形) .
这可能吗?
例如
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框架,用于:
Introspect underlying UIKit components from SwiftUI
在这种情况下,它用于取消选择按下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 = [=10=] }
.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)
}
}
}
可能的方法是使用自定义人字形制作行,如下面的演示(使用 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 在实际标签内容后面放置了一个带有空标签的 NavigationLink
。这样您就可以获得正确的人字形符号。
对于 isActive
绑定,您可以只使用 .constant(false)
绑定,该绑定始终 return false 且无法更改。
这将生成一个看起来与 NavigationLink 完全一样的行,但其行为却与 Button 类似。不幸的是,这还包括用户必须单击 label-content(文本)才能激活按钮的缺点,而不能只单击单元格的空 space。
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()
])
}
}
}
}