Our DNA is written in Swift
Jump

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

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

  1. Run it in iPad simulator in Landscape orientation
  2. Notice that it shows “Africa/Asmara Detail” on the right side, but there is no selection highlight on the list on the left
  3. If you click any row, then selection highlight is updated, as is the detail view
  4. While at the top of the list, press the arrow button above the list
  5. Notice that nothing changes
  6. 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
  7. Rotate to Portrait orientation (which hides the List as soon as a selection is being made)
  8. Scroll to the top of the list
  9. Tap the arrow button again, nothing happens
  10. 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:

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.


Also published on Medium.

Pages: 1 2


Categories: Bug Reports

Leave a Comment

%d bloggers like this: