Home > Software design >  SwiftUI wheel picker selection skips back to first item when scrolling
SwiftUI wheel picker selection skips back to first item when scrolling

Time:12-17

I have scoped probably the entirety of the internet and cannot find the answer to this, hence me reaching out.

I am trying to use the SwiftUI wheel picker for the user to make a language selection, but the picker is sticking to the first item in the list and is not scrolling to a new selection when trying to scroll through. This happens on both the simulator and a physical device.

I've spent the day reading all sorts of blogs, forums, questions, tutorials... all of it. From what I can tell from my code, it looks like everything is in order, but obviously I'm missing something!

Can someone please help me diagnose this? Code and environment details below.

The wheel picker within my view:

Picker("", selection: $model.selectedLanguageIndex, content: {
    ForEach(0..<model.languages.count, id: \.self) { index in
        Text(model.languages[index].name).tag(index)
    }
}).pickerStyle(.wheel)

The view has a view model declared:

@StateObject private var model = MyView.viewModel()

And the view also has an onAppear function at the parent element outer tag:

.onAppear(perform: model.load)

The view model looks like this:

extension MyView {
    class viewModel: ObservableObject {
        @Published var languages = [language]()
        @Published var selectedLanguageIndex = 0
        
        func load() {
            MyService.getLanguages { (success, error, languages) in
                guard success, error == nil, let languages = languages, !languages.isEmpty else { return }
                DispatchQueue.main.async { self.languages = languages }
            }
        }
    }
}

And the language model being used with the languages collection:

struct language: Hashable, Identifiable {
    let id: String
    let code: String
    let name: String
}

Environment:

Xcode 13.2
Mac Mini M1 2020 macOS Monterey (Dev machine)
iPhone 11 Pro Max iOS 15.1 (Physical device used for testing)

Any help at all would be greatly appreciated!

CodePudding user response:

I could not replicate your issue. All works well for me with the following test code. On Mac Monterey, Xcode 13.2, target ios 15 and catalyst 12.

Does this test code work for you? If so your issue is probably in some other code that you are not showing.

Here is my test code:

import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    @StateObject private var model = ContentView.viewModel()

    var body: some View {
        Picker("", selection: $model.selectedLanguageIndex, content: {
            ForEach(0..<model.languages.count, id: \.self) { index in
                Text(model.languages[index].name).tag(index)
            }
        }).pickerStyle(.wheel)
            .onAppear {
                model.load()
            }
    }
}

extension ContentView {
    class viewModel: ObservableObject {
        @Published var languages = [Language]()
        @Published var selectedLanguageIndex = 0
        
        func load() {
//            MyService.getLanguages { (success, error, languages) in
//                guard success, error == nil, let languages = languages, !languages.isEmpty else { return }
//                DispatchQueue.main.async { self.languages = languages }
//            }
            // for testing
            languages = [Language(id: "1", code: "1", name: "name 1"),
                         Language(id: "2", code: "2", name: "name 2"),
                         Language(id: "3", code: "3", name: "name 3"),
                         Language(id: "4", code: "4", name: "name 4")]
        }
    }
}

struct Language: Hashable, Identifiable {
    let id: String
    let code: String
    let name: String
}

Note: personally I would have my viewModel outside of an extension to a View.

  • Related