14

The selected row remains grey after navigating back from the detail view. Happening both on simulator and real device, only on iOS 14. Does anyone know how to remove it so it behaves the same as on iOS 13 (doesn't remain selected)? This is the only code in the project. (No other navigation's or anything).

let items = ["item1", "item2"]

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello")
                
                List(items, id: \.self) { item in
                    NavigationLink(destination: Text(item)) {
                        Text(item)
                    }
                }
                .listStyle(PlainListStyle())
            }
        }
//        .navigationViewStyle(StackNavigationViewStyle()) // didn't solve the problem
    }
}

This is how it looks

boldi24
  • 143
  • 1
  • 6
  • Did you find any way to work around? I regret that I used `SwiftUI` for my new project! – geek1706 Sep 24 '20 at 09:18
  • It's ridiculous how Apple just breaks things... And it's a simple list.... What I did is use List for iOS13 and use LazyVStack on iOS14. But would be nice if List would just work on iOS14 too. – boldi24 Sep 24 '20 at 09:27
  • On iOS 15 at least the grey background fades out after short while – onmyway133 Jun 15 '22 at 14:43

6 Answers6

16

This is the trick. Just create a ZStack and put an empty button above.

var body: some View {
    List {
        ForEach(data, id: \.self) { item in
            ZStack {
                Button("") {}
                NavigationLink(destination: ItemView(item: item)) {
                    ItemRow(item: item)
                }
            }
        }
    }
}
Beader Chen
  • 176
  • 1
  • 3
2

I had the same problem as soon as I used StackNavigationViewStyle(). The issue resolved itself for me by using DefaultNavigationViewStyle().

Cameron
  • 542
  • 5
  • 13
1

Here is the way I made it work. I have found some very rare cases where there is a bit of a lag for the highlight to disappear, but so far it helped a lot. This example uses the MVVM pattern, hopefully you get the idea.

You can access the underlying UITableView behind the SwiftUI List with this third party library :

https://github.com/siteline/SwiftUI-Introspect

and then you can store the tableView instance, and flush the selection when the table appears and disappears (somehow it worked better to do it in both, as those blocks may execute with a bit of lag depending on how aggressively the user navigates)

List {
// ...
}
.introspectTableView { tableView in
                         self.viewModel.bindToTableView(tableView)
                      }
.onAppear(perform: {
      self.viewModel.clearTableViewSelection()
})
.onDisappear(perform: {
      self.viewModel.clearTableViewSelection()
})

And in the viewModel, here are the functions

func bindToTableView(_ tableView: UITableView) {
    self.tableView = tableView
}

func clearTableViewSelection() {
    // This is a iOS14 hack that prevents clicked cell background view to remain highlighted when we come back to the screen
    if #available(iOS 14, *){
        DispatchQueue.main.async {
            if let selectedIndexPath = self.tableView?.indexPathForSelectedRow {
                self.tableView?.deselectRow(at: selectedIndexPath, animated: false)
                if let selectedCell = self.tableView?.cellForRow(at: selectedIndexPath) {
                    selectedCell.setSelected(false, animated: false)
                }
                
            }
        }
    }
}
Tao-Nhan Nguyen
  • 5,508
  • 2
  • 13
  • 9
0

I actually found a workaround with lazystack and then putting the row/cell in an Hstack together with some padding and a divider. But the performance is way worse than with a list.

Edit If you put the list outside of another View (in your example dont embed it in a VStack) it will work fine. So you have to put your list in a separate View-Struct and embed this one in your ContentView. Something like this:

    struct ExtractedListView: View {
     var listItems:[something]
        List(listItems, id: \.self) { item in
           NavigationLink(destination: Text(item)) {
             Text(item)
          }
    }


struct ContentView : View {
   NavigationView {
    VStack {
       Text("Hello")
       ExtractedListView(listItems: items)
    }
  }
}
phil Schn
  • 17
  • 3
  • I'm also using LazyVStack but it's only good for ios14. So would be nice if Apple fixed the List. – boldi24 Sep 27 '20 at 12:09
  • The worst part of this is, that my iPad Version of the app looked really professional on iOS13. I only had to tweak two little things regarding NavigationViews and Links. It looked really cool. So cool that I used it to show of SwuftUIs awesome features. Now on iPad it is even worse then the "Bugs" on iPhone under iOS14... different colors when a cell is clicked, everything seems to be highlighted in the List. I don't know how they did not check if things regarding List() and NavigationView/-Link would break unter iOS14. I guess over 60% of all Apps use Tables... – phil Schn Sep 29 '20 at 08:55
  • 1
    Still the same problem after putting the List into its own View struct. If you could share a working example copied from Xcode then I'd very much appreciate it. – boldi24 Sep 30 '20 at 15:07
0

You can wrap your view like this, it is useful especially if you are using list etc. This solution also gets rid of the caret.

ZStack {
     NavigationLink(destination: DestinationView()) {
         EmptyView()
     }

     Rectangle().background(Color(UIColor.systemBackground)).foregroundColor(Color(UIColor.systemBackground))
                    
     ViewToClick()
}
papa
  • 3
  • 1
0

Here is what worked for me:

@State var selection: Int? = nil

var body: some View {
    List {
        ForEach(self.model.data, id: \.self) { item in
            ZStack {
                
                Button("") {
                    self.selection = item.id
                }
                NavigationLink(destination: ItemView(item: item), tag: item.id, selection: self.$selection) {
                    Spacer()
                }.hidden()
                ItemRow(item: item)

            }
            
        }
    }
}
lorenzo
  • 1,487
  • 1
  • 17
  • 25