不带NavigationLink的SwiftUI列表显示指示器

cig3rfwq  于 2023-06-21  发布在  Swift
关注(0)|答案(8)|浏览(84)

我正在寻找一种解决方案,以显示披露指示符chevron,而不需要将我的视图 Package 到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,而不需要将其 Package 到NavigationLink
我已经尝试用chevron.right SF符号伪造指示器,但该符号与默认的iOS符号不匹配。顶部默认为底部为chevron.right

6yoyoihd

6yoyoihd1#

这绝对是可能的。
您可以使用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的结果相同,并且还按照交互的预期突出显示/取消突出显示行。

vcirk6k6

vcirk6k62#

希望这就是你要找的。你可以将项目添加到一个HStack中,并在中间插入一个Spacer,假装它是一个Link:

HStack {
                    Text("Item 1")
                    Spacer()
                    Button(action: {

                    }){
                        Image(systemName: "chevron.right")
                            .font(.body)
                    }
                }
3npbholx

3npbholx3#

已经提交的答案不能说明一件事:点击时单元格的突出显示。在我的答案底部的图片中看到About Peek-a-View单元格-它被突出显示,因为我在截图时按了它。
我的解决方案同时考虑了这个的V形:

Button(action: { /* handle the tap here */ }) {
    NavigationLink("Cell title", destination: EmptyView())
}
.foregroundColor(Color(uiColor: .label))

Button的出现似乎是在通知SwiftUI单元格何时被点击;简单地添加onTapGesture()是不够的。
这种方法唯一的缺点是需要指定.foregroundColor();如果没有它,按钮文本将改为蓝色。

ne5o7dgx

ne5o7dgx4#

在iOS15中,以下是更好的匹配,因为其他解决方案有点太大,不够大胆。它也将调整大小,以更好地不同的显示比例比指定字体大小更好。

HStack {
    Text("Label")
    Spacer()
    Image(systemName: "chevron.forward")
      .font(Font.system(.caption).weight(.bold))
      .foregroundColor(Color(UIColor.tertiaryLabel))
}

如果有一个官方的方法来做这件事就好了。更新每一个操作系统调整是恼人的。

ecr0jaav

ecr0jaav5#

我找到了一个原始的解决方案。用手插入图标不会带来完全相同的外观。
技巧是使用带有“isActive”参数的初始化器,并传递一个始终为false的本地绑定。所以NavigationLink等待一个永远不会发生的编程触发事件。

// use this initializer
NavigationLink(isActive: <Binding<Bool>>, destination: <() -> _>, label: <() -> _>)

您可以将一个空闭包传递给destination参数。它永远不会被调用,无论如何。要执行某些操作,您可以在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
        }
    }
}
nkcskrwz

nkcskrwz6#

为了便于访问,您可能需要模仿UIKit版本的披露指示器。* * 你不需要以这种方式实现它,但如果你使用例如你可能想要这样的测试设备来保持测试的成功**
显然,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)
    }
}
3qpi33ja

3qpi33ja7#

或者创建一个假的并使用它,即使你点击你可以调用你的事件。

NavigationLink(destination: EmptyView()) {
            HStack {
                Circle()
                 Text("TITLE")  
               
            }
        }
        .contentShape(Rectangle())
        .onTapGesture {
            print("ALERT MAYBE")
        }
vlurs2pr

vlurs2pr8#

我创建了一个自定义的NavigationLink
1.添加action API(而不是推送View
1.显示披露指示器
1.确保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() })
   }
}

相关问题