I want to set the selected row in a List programmatically.
In my example below via 2 Buttons.
struct ContentView: View {
@State private var selection = 2
var body: some View {
VStack {
List() {
//List(selection: $selection) {. // does not compile
Text("Line 0").tag(1)
Text("Line 1").tag(1)
Text("Line 2").tag(2)
Text("Line 3").tag(3)
Text("Line 4").tag(4)
Text("Line 5").tag(5)
}
.listStyle(SidebarListStyle())
Text("Selected Item :\(self.selection)")
HStack {
Button(action: {if (self.selection < 5 ) { self.selection += 1 }} ) {Text("⬇︎")}
Button(action: {if (self.selection > 0 ) { self.selection -= 1 }} ) {Text("⬆︎")}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
trying to make the List selectable like this:
List(selection: $selection)
does not compile.
Compiler complains: Unable to infer complex closure return type; add explicit type to disambiguate
Previously, with UIKit, one had to use a UITableView and implement delegate and data source methods (e.g. didSelectRowAt) to provide row content and navigate between views when a row is selected. Since SwiftUI is declarative, the content of each row is provided at the time of declaring the List.
Since SwiftUI is declarative, the content of each row is provided at the time of declaring the List. In addition, we can now use a NavigationLink to handle navigation between views.
The disclosure indicator arrow on the right is provided by SwiftUI for this particular type of List. The label is stretched out to the full width of the row to give more room to hit the gesture recognizer. More on that next.
We will add a struct called DetailsView that will be shown when a row on the List is selected. This view will show the emoji, its name, as well as a short description about the emoji. Our DetailsView will look like so:
Selection type must be optional. Find below fixed code.
struct TestListSelectionOnAction: View {
@State private var selection: Int? = 2 // optional !!
var body: some View {
VStack {
List(selection: $selection) {
Text("Line 0").tag(0)
Text("Line 1").tag(1)
Text("Line 2").tag(2)
Text("Line 3").tag(3)
Text("Line 4").tag(4)
Text("Line 5").tag(5)
}
.listStyle(SidebarListStyle())
Text("Selected Item :\(self.selection ?? -1)")
HStack {
Button(action: {
if (self.selection! < 5 ) { self.selection! += 1 }} ) {Text("⬇︎")}
Button(action: {
if (self.selection! > 0 ) { self.selection! -= 1 }} ) {Text("⬆︎")}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
thanks to Introspect: https://github.com/siteline/SwiftUI-Introspect
handle iPad Sidebar unable to set default row & make selected style visible in initial:
Example:
struct TempData: Identifiable {
var id: Int
var title: String
}
struct TempView: View {
// handle selection nil: when detail view pushs view, selection == nil
@State private var keepSelection: Int = 2
// bind list selected row
@State private var selection: Int? = 2 // set default row
private var dataArr: [TempData] = [TempData(id: 1, title: "one"),
TempData(id: 2, title: "two"),
TempData(id: 3, title: "three")]
var body: some View {
List(selection: $selection) {
ForEach(dataArr.indices) { index in
NavigationLink(destination: Text("\(dataArr[index].title)").onAppear {
keepSelection = (selection != nil ? selection! : keepSelection)
}, tag: dataArr[index].id, selection: $selection) {
HStack {
Text("\(dataArr[index].title)")
}
}
.introspectTableViewCell(customize: { cell in
// import Introspect
// https://github.com/siteline/SwiftUI-Introspect
cell.selectionStyle = .none
cell.backgroundColor = .systemGroupedBackground
})
.tag(dataArr[index].id) // or use enum
.listRowBackground(keepSelection == dataArr[index].id ? Color.accentColor.cornerRadius(10.0): Color(UIColor.systemGroupedBackground).cornerRadius(10))
}
}
}
}
It won't compile because the tags are not unique. You are setting tag 1 twice. It can not identify the value, thats why List(selection: $selection)
does not work either.
List() {
//List(selection: $selection) {. // should compile now
Text("Line 0").tag(0)
Text("Line 1").tag(1)
Text("Line 2").tag(2)
Text("Line 3").tag(3)
Text("Line 4").tag(4)
Text("Line 5").tag(5)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With