Reputation: 726
I'm struggling with a simple solution I can't find. I want to build a picker which shows the flags and selects the Language code from the other array. There must be a simple solution. so long I helped myself with this ugly onChange
crutch.
Any suggestions?
struct LanguageView: View {
@AppStorage ("language")var language: String = "de"
@State private var flag: String = ""
var languages = ["de", "en", "pl"]
var languageFlags = ["π©πͺ", "π¬π§ πΊπΈ", "π΅π±" ]
var body: some View {
VStack{
HStack{
Picker("", selection: $flag) {
ForEach(languageFlags, id: \.self) {
Text($0)
.font(.caption2)
}
}
.pickerStyle(SegmentedPickerStyle())
}.onChange(of: flag, perform: { value in
if flag == "π©πͺ" {language = "de"}
if flag == "π¬π§ πΊπΈ" {language = "en"}
if flag == "π΅π±" {language = "pl"}
})
}
.environment(\.locale, .init(identifier: language))
}
}
Upvotes: 2
Views: 129
Reputation: 1
I think this would also a good answer for your need, you should define a custom type like I did! With my code, the selected Language saved directly and you should not worry about it! more secure I would say.
import SwiftUI
struct ContentView: View {
var body: some View {
LanguageView()
}
}
struct Language: Hashable {
let language: String
let flag: String
}
let languageArray: [Language] = [Language(language: "de", flag: "π©πͺ"), Language(language: "en", flag: "π¬π§ πΊπΈ"), Language(language: "pl", flag: "π΅π±")]
struct LanguageView: View {
@AppStorage ("language")var selectedFlag: Int = 0
var body: some View {
VStack{
HStack{
Picker("", selection: $selectedFlag) {
ForEach(languageArray.indices, id: \.self) { index in
Text(languageArray[index].flag)
.font(.caption2)
}
}
.pickerStyle(SegmentedPickerStyle())
}
.onAppear() { print("language is: " + languageArray[selectedFlag].language) }
.onChange(of: selectedFlag) { newValue in
print("language is: " + languageArray[newValue].language)
}
}
}
}
Upvotes: 1
Reputation: 15015
Use enum for languages and confirm to the CaseIterable protocol so that you can itereate over all of its cases (languages).
An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code. https://docs.swift.org
enum Language: String, CaseIterable {
case de = "π©πͺ"
case en = "π¬π§ πΊπΈ"
case pl = "π΅π±"
var name: String {
get { return String(describing: self) }
}
}
struct LanguageView: View {
@AppStorage("language") var language: Language = .de
var body: some View {
VStack {
HStack {
Picker("", selection: $language) {
ForEach(Language.allCases, id: \.self) { language in
Text(language.rawValue)
.font(.caption2)
}
}
.pickerStyle(SegmentedPickerStyle())
}
}
.environment(\.locale, .init(identifier: language.name))
}
}
Upvotes: 0
Reputation: 131491
Everybody else posted an answer that preserved your combining the flags for the US and the UK. If you need to map from a user-selected flag to a language, a Dictionary seems like the obvious choice:
let flagsAndLanguages = ["π©πͺ": "de", "π¬π§" : "en", "πΊπΈ": "en", "π΅π±" : "pl"]
let aFlag = "π¬π§"
func languageForFlag(_ flag: String) -> String {
return flagsAndLanguages[aFlag] ?? "unknown"
}
print("The lanagugage for the flag \(aFlag) is '\(languageForFlag(aFlag))'")
This outputs The lanagugage for the flag π¬π§ is 'en'
.
Looking up entries in a Dictionary is extremely fast. KeyValuePairs
, in contrast, are slower, but preserve ordering. I don't think you need to preserve a specific order of your flags/languages, do you?
Upvotes: 0
Reputation: 2882
You could also have Array of type [(String,String)]
a Tuple
. If you donβt want parameter names, you can also access them using indices 0
and 1
struct LanguageView: View {
@AppStorage ("language")var language: String = "de"
@State private var flag: Int = 0
var languageFlags = [(flag:"π©πͺ",language:"de"), (flag:"π¬π§ πΊπΈ",language:"en"), (flag:"π΅π±",language:"pl")]
var body: some View {
VStack{
HStack{
Picker("", selection: $flag) {
ForEach(languageFlags.indices) { (index) in
Text(languageFlags[index].flag)
.font(.caption2)
}
}
.pickerStyle(SegmentedPickerStyle())
}.onChange(of: flag, perform: { index in
language = languageFlags[index].language
})
}
.environment(\.locale, .init(identifier: language))
}
}
Upvotes: 0
Reputation: 54621
You can create an enum for Language
:
enum Language: String, CaseIterable {
case de, en, pl
var flag: String {
switch self {
case .de:
return "π©πͺ"
case .en:
return "π¬π§ πΊπΈ"
case .pl:
return "π΅π±"
}
}
}
Then, you don't need extra @State
variables nor onChange
:
struct LanguageView: View {
@AppStorage("language") var language: Language = .de
var body: some View {
VStack {
HStack {
Picker("", selection: $language) {
ForEach(Language.allCases, id: \.self) {
Text($0.flag)
.font(.caption2)
}
}
.pickerStyle(SegmentedPickerStyle())
}
}
.environment(\.locale, .init(identifier: language.rawValue))
}
}
Upvotes: 1