SwiftUI: Laziness of List Interferes with Selection and Presentation of Detail

iOS 14 introduces some laziness in certain views, like for example there are now lazy variants of HStack and VStack. I’ve been working on a SwiftUI-version of an app of mine and the findings of my research for these bugs led me to believe that Apple added some lazy optimisations to Lists as well. 

Unfortunately those optimisations seem to be breaking selection and presentation of detail views to a degree that they would be show stoppers for any universal app relying on List and its automatic promotion to being a split view on iPad.

I filed this as FB8521674 in the Apple Feedback App. I am posting the full report here as well as these findings might be helpful to other developers who were as stuck as I am, hoping that Apple will fix this issue .

Bug Report

On iPad, List is supposed to present the destination of NavigationLinks when the link’s tag matches the selection binding’s value. But that only occurs if the referenced row is presently visible.

Setting selection programmatically only presents the detail view if the referenced row is presently visible. That goes both for setting the selected binding to a value before the list appears as well as setting it while it is visible.

The selection highlight is not being updated by programmatic selection. Also, if you hide the list on iPad via the button on the top left and show it again, the selection highlight also disappears.

Steps to Reproduce

  • Open the attached sample project

  • Run it in iPad simulator in Landscape orientation

  • Notice that it shows “Africa/Asmara Detail” on the right side, but there is no selection highlight on the list on the left

  • If you click any row, then selection highlight is updated, as is the detail view

  • While at the top of the list, press the arrow button above the list

  • Notice that nothing changes

  • Now scroll down the list. As soon as the row for “America/Adak” appears, the detail view is being updated, but the selection highlight is still missing

  • Rotate to Portrait orientation (which hides the List as soon as a selection is being made)

  • Scroll to the top of the list

  • Tap the arrow button again, nothing happens

  • Scroll down until “America/Adak” becomes visible, now the detail view gets updated (selection highlight does not show) and the list disappears

What I expected to happen

  • when the app shows in landscape (#3) the “Africa/Asmera” row should be highlighted

  • when you tap the arrow (#5) the “America/Adak” row should be highlighted (and scrolled to) and the related detail view be presented

  • when in Portrait, the sudden dismissal of the list is confusing. I would prefer to have the auto-hiding only occur if the user makes a change of the selection. But if you must hide it, then at least the selection highlight should be visible

  • hiding and re-showing the list on iPad Landscape should preserve the selection highlight

What actually happened

  • programmatic change of the selection never updates the highlight

  • a detail page is only presented as soon as the referenced row becomes visible

  • if you are scrolling, on iPad Portrait, and a selected item becomes visible the list is suddenly dismissed

  • hiding and re-showing the list (iPad Landscape) doesn’t preserve selection highlight

Sample Project


The sample project is so short that I can reproduce it here for you:
Code Block
import SwiftUI
@main
struct SelectionBugApp: App {
// the navigation presentation is only done on the
// initially visible rows
// selection is never updated
@State var selectedID: String? = "Africa/Asmara"
var body: some Scene {
WindowGroup {
NavigationView {
List(selection: $selectedID) {
ForEach(TimeZone.knownTimeZoneIdentifiers,
id: \.self) { identifier in
NavigationLink(identifier,
  destination: Text("\(identifier) Detail"),
  tag: identifier,
  selection: $selectedID)
}
}
.navigationTitle("Time Zones")
.navigationBarItems(trailing:
Button(action: {
// this presents the navigation destination,
// but only if the row has been visible
// selection is never updated
self.selectedID = "America/Adak"
}, label: {
Image(systemName: "location.fill")
})
)
}
    }
  }
}

Just post it into a new iOS SwiftUI app and you can follow along.
The header comment states List selection binding (when not in editing mode) is Mac only. I'd love to hear why!
Has this ever been solved yet? I really need this for my apps also.
Second attempt to find out the resolution of this issue. Has this ever been solved yet? I really need this for my apps also.

I'm also looking for any workarounds to fix this behavior in iOS 14. I haven't tested iOS 15's ColumnNavigationViewStyle yet.

I'm still seeing this in macOS 12.1 Monterey.

SwiftUI: Laziness of List Interferes with Selection and Presentation of Detail
 
 
Q