title: How to make List with single selection with SwiftUI
body: <p>I am creating single selection list to use in different places in my app.</p>
  
  <hr>
  
  <p>Questions:</p>
  
  <p>Is there an easy solution I don't know?</p>
  
  <p>If there isn't, how can I finish my current solution?</p>
  
  <hr>
  
  <p>My goal:</p>
  
  <ol>
  <li>List with always only one item selected or one or none item selected (depending on configuration)</li>
  <li>Transparent background</li>
  <li>On item select - perform action which is set as parameter via init() method. (That action requires selected item info.)</li>
  <li>Change list data programmatically and reset selection to first item</li>
  </ol>
  
  <p>My current solution looks like:
  <a href="https://i.stack.imgur.com/kTanK.jpg" rel="noreferrer">List view with second item selected</a></p>
  
  <p>I can't use Picker, because outer action (goal Nr. 3) is time consuming. So I think it wouldn't work smoothly.
  Most probably there is solution to my problem in SwiftUI, but either I missed it, because I am new to swift or as I understand not everything works perfectly in SwiftUI yet, for example: transparent background for List (which is why i needed to clear background in init()).</p>
  
  <p>So I started implementing selection myself, and stoped here:
  My current solution does not update view when item(Button) is clicked. (Only going out and back to the page updates view). And still multiple items can be selected.</p>
  
  <pre><code>import SwiftUI
  
  struct ModuleList: View {
      var modules: [Module] = []
      @Binding var selectionKeeper: Int
      var Action: () -&gt; Void
  
  
      init(list: [Module], selection: Binding&lt;Int&gt;, action: @escaping () -&gt; Void) {
          UITableView.appearance().backgroundColor = .clear
          self.modules = list
          self._selectionKeeper = selection
          self.Action = action
      }
  
      var body: some View {
          List(){
              ForEach(0..&lt;modules.count) { i in
                  ModuleCell(module: self.modules[i], action: { self.changeSelection(index: i) })
                  }
          }.background(Constants.colorTransparent)
      }
  
      func changeSelection(index: Int){
          modules[selectionKeeper].isSelected =  false
          modules[index].isSelected = true
          selectionKeeper = index
          self.Action()
      }
  }
  
  struct ModuleCell: View {
      var module: Module
      var Action: () -&gt; Void
  
      init(module: Module, action: @escaping () -&gt; Void) {
          UITableViewCell.appearance().backgroundColor = .clear
          self.module = module
          self.Action = action
      }
  
      var body: some View {
          Button(module.name, action: {
              self.Action()
          })
              .frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
              .modifier(Constants.CellSelection(isSelected: module.isSelected))
      }
  }
  
  class Module: Identifiable {
      var id = UUID()
      var name: String = ""
      var isSelected: Bool = false
      var address: Int
  
      init(name: String, address: Int){
          self.name = name
          self.address = address
      }
  }
  
  let testLines = [
      Module(name: "Line1", address: 1),
      Module(name: "Line2", address: 3),
      Module(name: "Line3", address: 5),
      Module(name: "Line4", address: 6),
      Module(name: "Line5", address: 7),
      Module(name: "Line6", address: 8),
      Module(name: "Line7", address: 12),
      Module(name: "Line8", address: 14),
      Module(name: "Line9", address: 11),
      Module(name: "Line10", address: 9),
      Module(name: "Line11", address: 22)
  ]
  </code></pre>
  
  <hr>
  
  <h2>Testing some ideas:</h2>
  
  <p>Tried adding @State array of (isSelected: Bool) in ModuleList and binding it to Module isSelected parameter that MIGHT update view... But failed then populating this array in init(), because @State array parameter would stay empty after .append()... Maybe adding function setList would have solved this, and my goal Nr. 4. But I was not sure if this would really update my view in the first place.</p>
  
  <pre><code>struct ModuleList: View {
       var modules: [Module] = []
       @State var selections: [Bool] = []
  
  
       init(list: [String]) {
           UITableView.appearance().backgroundColor = .clear
           selections = [Bool] (repeating: false, count: list.count) // stays empty
           let test = [Bool] (repeating: false, count: list.count) // testing: works as it should
           selections = test
           for i in 0..&lt;test.count { // for i in 0..&lt;selections.count {
               selections.append(false)
               modules.append(Module(name: list[i], isSelected: $selections[i])) // Error selections is empty
           }
       }
  
       var body: some View {
           List{
               ForEach(0..&lt;modules.count) { i in
                   ModuleCell(module: self.modules[i], action: { self.changeSelection(index: i) })
                   }
           }.background(Constants.colorTransparent)
       }
       func changeSelection(index: Int){
           modules[index].isSelected = true
       }
   }
  
   struct ModuleCell: View {
       var module: Module
       var Method: () -&gt; Void
  
       init(module: Module, action: @escaping () -&gt; Void) {
           UITableViewCell.appearance().backgroundColor = .clear
           self.module = module
           self.Method = action
       }
  
       var body: some View {
           Button(module.name, action: {
               self.Method()
           })
               .frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
               .modifier(Constants.CellSelection(isSelected: module.isSelected))
       }
   }
  
   struct Module: Identifiable {
       var id = UUID()
       var name: String = ""
       @Binding var isSelected: Bool
  
       init(name: String, isSelected: Binding&lt;Bool&gt;){
           self.name = name
           self._isSelected = isSelected
       }
   }
  
   let testLines = ["Line1","Line2","Line3","Line4"
   ]
  </code></pre>