[英]SwiftUI List disclosure indicator without NavigationLink
我正在尋找一種解決方案來顯示披露指示符 chevron 而無需將我的視圖包裝到NavigationLink
中。 例如,我想顯示指示器但不導航到新視圖,而是顯示模式。
我找到了很多隱藏指示器按鈕的解決方案,但沒有一個可以解釋如何添加一個。 在當前的 SwiftUI 版本中,這甚至可能嗎?
struct MyList: View {
var body: some View {
NavigationView {
List {
Section {
Text("Item 1")
Text("Item 2")
Text("Item 3")
Text("Item 4")
}
}
}
}
例如,我想將披露指示符添加到Item 1
,而無需將其包裝到NavigationLink
中
我已經嘗試使用chevron.right
SF 符號來偽造指標,但該符號與默認的 iOS 符號 100% 不匹配。 頂部是默認底部是chevron.right
。
希望這是您正在尋找的。 您可以將項目添加到 HStack 並在之間使用 Spacer 假裝它是一個鏈接:
HStack {
Text("Item 1")
Spacer()
Button(action: {
}){
Image(systemName: "chevron.right")
.font(.body)
}
}
這絕對是可能的。
您可以使用Button
和非功能NavigationLink
的組合來實現您想要的。
在NavigationLink
上添加以下擴展。
extension NavigationLink where Label == EmptyView, Destination == EmptyView {
/// Useful in cases where a `NavigationLink` is needed but there should not be
/// a destination. e.g. for programmatic navigation.
static var empty: NavigationLink {
self.init(destination: EmptyView(), label: { EmptyView() })
}
}
然后,在您的List
中,您可以對行執行以下操作:
// ...
ForEach(section.items) { item in
Button(action: {
// your custom navigation / action goes here
}) {
HStack {
Text(item.name)
Spacer()
NavigationLink.empty
}
}
}
// ...
以上產生的結果與您使用NavigationLink
相同,並且還按預期在交互中突出顯示/取消突出顯示該行。
在 iOS15 中,以下是更好的匹配,因為其他解決方案有點太大而且不夠大膽。 與指定字體大小相比,它還可以更好地調整到不同的顯示比例。
HStack {
Text("Label")
Spacer()
Image(systemName: "chevron.forward")
.font(Font.system(.caption).weight(.bold))
.foregroundColor(Color(UIColor.tertiaryLabel))
}
如果有一種官方的方式來做到這一點會很好。 更新每個操作系統調整很煩人。
或者也許創建一個假的並使用它,即使你點擊你也可以調用你的事件。
NavigationLink(destination: EmptyView()) {
HStack {
Circle()
Text("TITLE")
}
}
.contentShape(Rectangle())
.onTapGesture {
print("ALERT MAYBE")
}
我找到了一個原始的解決方案。 手動插入圖標不會帶來完全相同的外觀。
訣竅是使用帶有“isActive”參數的初始化程序並傳遞一個始終為假的本地綁定。 所以 NavigationLink 等待一個永遠不會發生的以編程方式觸發的事件。
// use this initializer
NavigationLink(isActive: <Binding<Bool>>, destination: <() -> _>, label: <() -> _>)
您可以將空閉包傳遞給目標參數。 無論如何,它永遠不會被調用。 要執行一些操作,您可以在 ZStack 的頂部放置一個按鈕。
func navigationLinkStyle() -> some View {
let never = Binding<Bool> { false } set: { _ in }
return ZStack {
NavigationLink(isActive: never, destination: { }) {
Text("Item 1") // your list cell view
}
Button {
// do your action on tap gesture
} label: {
EmptyView() // invisible placeholder
}
}
}
對於可訪問性,您可能需要模仿UIKit
版本的披露指示器。 您本身不需要以這種方式實現它,但如果您使用例如 Appium 進行測試,您可能希望這樣來保持測試成功
顯然UIKit
的披露指示器是一個禁用按鈕,具有一些可訪問性值,所以這里是解決方案:
struct DisclosureIndicator: View {
var body: some View {
Button {
} label: {
Image(systemName: "chevron.right")
.font(.body)
.foregroundColor(Color(UIColor.tertiaryLabel))
}
.disabled(true)
.accessibilityLabel(Text("chevron"))
.accessibilityIdentifier("chevron")
.accessibilityHidden(true)
}
}
已經提交的答案並沒有說明一件事:點擊時單元格的突出顯示。 請參閱我的答案底部圖像中的About Peek-a-View
單元格 - 它被突出顯示,因為我在截取屏幕截圖時按下了它。
我的解決方案同時考慮了這一點和雪佛龍:
Button(action: { /* handle the tap here */ }) {
NavigationLink("Cell title", destination: EmptyView())
}
.foregroundColor(Color(uiColor: .label))
當單元被點擊時, Button
的存在似乎會通知 SwiftUI; 僅僅添加一個onTapGesture()
是不夠的。
這種方法的唯一缺點是需要指定.foregroundColor()
; 沒有它,按鈕文本將改為藍色。
我創建了一個自定義NavigationLink
:
action
API (而不是必須推送一個View
)List
單元格選擇保持原樣MYNavigationLink(action: {
didSelectCell()
}) {
MYCellView()
}
import SwiftUI
struct MYNavigationLink<Label: View>: View {
@Environment(\.colorScheme) var colorScheme
private let action: () -> Void
private let label: () -> Label
init(action: @escaping () -> Void, @ViewBuilder label: @escaping () -> Label) {
self.action = action
self.label = label
}
var body: some View {
Button(action: action) {
HStack(spacing: 0) {
label()
Spacer()
NavigationLink.empty
.layoutPriority(-1) // prioritize `label`
}
}
// Fix the `tint` color that `Button` adds
.tint(colorScheme == .dark ? .white : .black) // TODO: Change this for your app
}
}
// Inspiration:
// - https://stackoverflow.com/a/66891173/826435
private extension NavigationLink where Label == EmptyView, Destination == EmptyView {
static var empty: NavigationLink {
self.init(destination: EmptyView(), label: { EmptyView() })
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.