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:
- The entire list element is still clickable.
- 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?