7

I'm quite new to Swift and coding in general so apologies if this is a super simple question.

I'm trying to add a button either side of a Picker to allow the user to move up/down the selections within the Picker (my Picker is populated from an Array) - I'm using this selection in another part of my App.

The code below works but only updates the example Text, but it does not update the selection: within the pickerto update correctly.

Any ideas what I'm doing wrong?

import SwiftUI

struct ContentView: View {
    
    let myArray = ["Period 1", "Period 2", "Period 3", "Period 4", "Period 5", "Period 6", "Period 7", "Period 8", "Period 9", "Period 10", "Period 11", "Period 12", "Period 13"]
    @State var currentIndex = 0
    
    var body: some View {
        VStack(spacing: 20) {
            
            HStack {
                Button(action: {
                    if currentIndex == 0 {
                    } else {
                        currentIndex -= 1
                    }
                }) {
                    Image(systemName: "chevron.left.circle")
                        .imageScale(.large)
                }
                .padding(2)
                .frame(maxWidth: .infinity, alignment: .leading)
                
                Picker(selection: $currentIndex, label: Text("Picker")) {
                    ForEach(myArray, id: \.self) {
                        Text($0)
                    }
                }
                
                Button(action: {
                    if currentIndex == 12 {
                    } else {
                        currentIndex += 1
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                }
                .padding(2)
                .frame(maxWidth: .infinity, alignment: .trailing)
                
            }
            .padding()
            
            Text("\(myArray[currentIndex])")

        }
    }
    
}

'''

2
  • Unrelated but maybe a Stepper would be a better choice than a Picker here. Commented Jan 20, 2022 at 12:19
  • Thanks, I have considered that (and have an example in code) but the UI didn't quite work for my use case. Commented Jan 20, 2022 at 12:23

1 Answer 1

10

The problem here is that you are programmatically updating your State variable currentIndex but you are not modifying the array selection. To make this work you need to iterate the array over the indices and not the elements so change the Picker code to this

Picker(selection: $currentIndex, label: Text("Picker")) {
    ForEach(myArray.indices) { index in
        Text(myArray[index])
    }
}

Here each item in the picker automatically gets the id of the raw value of index which matches with currentIndex which makes this work.

To work directly with the elements of the array here is an alternative solution where a new State variable is added to hold the selected string.

@State var currentSelection = ""
@State var currentIndex = 0 {
    didSet {
        currentSelection = myArray[currentIndex]
    }
}

The picker code gets changed to

Picker(selection: $currentSelection, label: Text("Picker")) {
    ForEach(myArray, id: \.self) { period in
        Text(period)
    }
}

but the rest of the code is the same since the buttons are still using currentIndex

Sign up to request clarification or add additional context in comments.

2 Comments

This is amazing, thank you so much for explaining where I was going wrong :) thank you!
Searched all over for for loading picker from array and setting it up properly. Great answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.