0

I have a List within a NavigationView where each view under List should have navigatable elements attached to it (cover image, user avatar + name, etc.) For example, clicking the cover image navigates to view A, while clicking the user's name/avatar navigates to view B. Sadly, in all cases, the entire list element was clickable and did not grant the intended behavior.

At first, I tried wrapping my content within a NavigationLink.

NavigationLink(destination: Text("Media"), tag: .media, selection: $selection) {
    WebImage(url: URL(string: activity.media?.coverImage?.extraLarge ?? ""))
        .resizable()
        .placeholder { color }
        .cornerRadius(8)
        .frame(width: 90, height: 135)
}

This causes an arrow to appear to indicate the view is navigatable for the user but is unwanted in this situation. It was also taking up a lot of space from the view unnecessarily.

My next attempt was to wrap the view and NavigationLink in a ZStack.

ZStack {
    NavigationLink(destination: Text("Media"), tag: .media, selection: $selection) {
        EmptyView()
    }.hidden()

    WebImage(url: URL(string: activity.media?.coverImage?.extraLarge ?? ""))
        .resizable()
        .placeholder { color }
        .cornerRadius(8)
}.frame(width: 90, height: 135)

The .hidden() modifier was applied to the NavigationLink to prevent the arrow from appearing when the image was transparent. While this solution both hides the arrow and cleans up the extra space, there are two issues:

  1. The entire list element is still clickable.
  2. A ZStack covered by the .frame modifier requires I know how large I want to make it. The user's name & avatar view can't easily overcome this dilemma.

Thirdly, I tried wrapping the view in a Button where the label was the cover image and the action was to change selection to navigate programmatically, but this brought the spacing issue from #1 and the overall issue of the list element being clickable.

I later discovered a solution that would cut down the previous issues I had, but brought one problem. To understand it, this is what my main activity view looks like:

NavigationView {
    List(viewModel.activities) { activity in
        ActivitySelectionView(activity: activity, selection: $selection)
    }.navigationTitle("Activity Feed")
}.onAppear {
    viewModel.fetchActivities()
}

By encapsulating List(...) {...} in a ScrollView and changing List to a ForEach, I was able to produce the output I wanted: clickable view within an element, the cover image became lighter when clicking on it, opposed to the list element becoming darker as a whole until let go, etc.

However, this is not a list. It does not look good, nor will it look better on other platforms (this is an iOS project). For example, this code does not respect the edges as a list does. It also does not include a divider, but the Divider struct can help. I feel this is not the right solution to this problem.

To sum it all up, how do I create a List inside a NavigationView where the list respects what views inside an element are navigatable?

Klay
  • 45
  • 2
  • 6
  • you have to use ScrollView for this purpose, you cannot use mo than one navigationLink inside a single cell in a List( you may use , but it does not give expected result /navigation) – YodagamaHeshan Nov 24 '20 at 02:38
  • could you provide the cell view/ a element of the List – YodagamaHeshan Nov 24 '20 at 02:43
  • Does this answer your question https://stackoverflow.com/a/63497954/12299030? – Asperi Nov 24 '20 at 04:22
  • @Asperi, while that solution does work, it's not the behavior I'm looking for sadly. The list's row content is all clickable, which is not what I'm looking for. – Klay Nov 24 '20 at 05:20

1 Answers1

0

I found an elegant solution to my problem, so I'd like to share it for people who may stumble upon this question in the future.

You need to use a ScrollView within the List {...} somewhere. In the ScrollView block, it's perfectly suitable to make certain elements in the list cell navigatable.

NavigationView {
  List(1..<11) { num in
    ScrollView {
      Text("\(num)!")

      NavigationLink(destination: Text("Number: \(num)")) {
        Text("Click me")
      }
    }
  }
}
Klay
  • 45
  • 2
  • 6