EXACountryPicker is a country picker controller for iOS8+ with an option to search. The list of countries is based on the ISO 3166 country code standard (http://en.wikipedia.org/wiki/ISO_3166-1). Also and the library includes a set of 250 public domain flag images.
The picker provides:
- Country Names
- Country codes - ISO 3166
- International Dialing Codes
- Flags
let picker = EXACountryPicker(style: .grouped)
picker.configuration = EXACountryPickerConfiguration(
allowedCountryCodes: nil, // or ["FR", "US", ...]
preferredCountryCodes: ["FR", "US"], // pinned section
showsRecentCountries: true, // persists last selections
recentCountriesLimit: 6,
showsCurrentLocation: true,
searchMatchesDialingCodeAndISOCode: true
)picker.theme = .system // follows dynamic system colors
// or build your own
picker.theme = EXACountryPickerTheme(
backgroundColor: .systemBackground,
countryNameFont: UIFont.systemFont(ofSize: 16, weight: .medium),
countryNameTextColor: .label,
searchBarBackgroundColor: .secondarySystemBackground
)Search is now diacritics-insensitive and matches:
- country name (prefix and contains)
- ISO code (optional)
- dialing code (optional)
*Note: current location is determined from the current region of the iPhone
EXACountryPicker is available through CocoaPods, to install it simply add the following line to your Podfile:
Swift 5 and later:
use_frameworks!
pod 'EXACountryPicker', '~> 1.0.3'
You can also use Swift Package Manager to add EXACountryPicker to your project:
- Go to File > Add Packages...
- Enter the repository URL:
https://github.com/exaland/EXACountryPicker.git - Select the version you want to use
- Click Add Package
Add the following to your Package.swift file:
dependencies: [
.package(url: "https://github.com/exaland/EXACountryPicker.git", from: "1.0.3")
]Then add EXACountryPicker to your target dependencies:
targets: [
.target(
name: "YourTarget",
dependencies: ["EXACountryPicker"]
)
]import SwiftUI
import EXACountryPicker
struct ContentView: View {
@State private var showPicker = false
@State private var selected: EXCountry?
var body: some View {
Button("Choose country") { showPicker = true }
.sheet(isPresented: $showPicker) {
CountryPickerView(
isPresented: $showPicker,
pickerTitle: "Select a Country",
configuration: .init(preferredCountryCodes: ["FR", "US"]),
theme: .system,
showCallingCodes: true
) { country in
selected = country
}
}
}
}Push EXACountryPicker from UIViewController
let picker = EXACountryPicker(style: .grouped)
navigationController?.pushViewController(picker, animated: true)Present EXACountryPicker from UIViewController
let picker = EXACountryPicker()
let pickerNavigationController = UINavigationController(rootViewController: picker)
self.present(pickerNavigationController, animated: true, completion: nil)/// delegate
picker.delegate = self
/// Optionally, set this to display the country calling codes after the names
picker.showCallingCodes = true
/// Flag to indicate whether country flags should be shown on the picker. Defaults to true
picker.showFlags = true
/// The nav bar title to show on picker view
picker.pickerTitle = "Select a Country"
/// The default current location, if region cannot be determined. Defaults to US
picker.defaultCountryCode = "US"
/// Flag to indicate whether the defaultCountryCode should be used even if region can be deteremined. Defaults to false
picker.forceDefaultCountryCode = false
/// The text color of the alphabet scrollbar. Defaults to black
picker.alphabetScrollBarTintColor = UIColor.black
/// The background color of the alphabet scrollar. Default to clear color
picker.alphabetScrollBarBackgroundColor = UIColor.clear
/// The tint color of the close icon in presented pickers. Defaults to black
picker.closeButtonTintColor = UIColor.black
/// The font of the country name list
picker.font = UIFont(name: "Helvetica Neue", size: 15)
/// The height of the flags shown. Default to 40px
picker.flagHeight = 40
/// Flag to indicate if the navigation bar should be hidden when search becomes active. Defaults to true
picker.hidesNavigationBarWhenPresentingSearch = true
/// The background color of the searchbar. Defaults to lightGray
picker.searchBarBackgroundColor = UIColor.lightGray
/// Advanced configuration (preferred/recent/search)
picker.configuration = .default
/// Theme (colors/fonts)
picker.theme = .systemfunc countryPicker(picker: EXACountryPicker, didSelectCountryWithName name: String, code: String) {
print(code)
}
func countryPicker(picker: EXACountryPicker, didSelectCountryWithName name: String, code: String, dialCode: String) {
print(dialCode)
}// or closure
picker.didSelectCountryClosure = { name, code in
print(code)
}
picker.didSelectCountryWithCallingCodeClosure = { name, code, dialCode in
print(dialCode)
}/// Returns the country flag for the given country code
///
/// - Parameter countryCode: ISO code of country to get flag for
/// - Returns: the UIImage for given country code if it exists
let flagImage = picker.getFlag(countryCode: code)
/// Returns the country name for the given country code
///
/// - Parameter countryCode: ISO code of country to get dialing code for
/// - Returns: the country name for given country code if it exists
let countryName = picker.getCountryName(countryCode: code)
/// Returns the country dial code for the given country code
///
/// - Parameter countryCode: ISO code of country to get dialing code for
/// - Returns: the dial code for given country code if it exists
let dialingCode = picker.getDialCode(countryCode: code)Alexandre MAGNIER - EXALAND CONCEPT exaland@gmail.com
Core based on work of @mustafaibrahim989
Designed for iOS 13+
EXACountryPicker is available under the MIT license. See the LICENSE file for more info.
If you use Swift Package Manager and the country flags don’t show up, it’s almost always a resources/bundle issue.
This library ships the images inside Sources/EXACountryPicker/assets.bundle/ and loads them from the package resources bundle:
- SwiftPM:
Bundle.module - CocoaPods:
Bundle(for: EXACountryPicker.self)
Make sure you’re using a version that declares the resources in Package.swift (SwiftPM):
assets.bundle/CallingCodes.plistEXACountryPicker.strings
If you’re integrating from source, verify Package.swift contains something like:
.target(
name: "EXACountryPicker",
path: "Sources/EXACountryPicker",
resources: [
.process("assets.bundle"),
.process("CallingCodes.plist"),
.process("EXACountryPicker.strings")
]
)If you recently switched from CocoaPods to SwiftPM (or updated the package), reset package caches in Xcode:
- File → Packages → Reset Package Caches
- File → Packages → Resolve Package Versions
- Product → Clean Build Folder
Also ensure you didn’t disable flags:
picker.showFlags = truegetFlag(countryCode:) expects an ISO country code like "FR", "US", not a dial code like "+33".
If you only have the dial code, you can use:
let flag = picker.getFlag(dialCode: "+33")If you enable Recent/Preferred/Current Location sections, the picker inserts dynamic sections at the top. A bug could cause the table to select a different country than the one tapped (section index offset issue). This has been fixed by correctly mapping displayed section indexes to the underlying data.
Section titles are now localizable/customizable through EXACountryPickerTheme.
Default localization keys:
EXACountryPicker.section.recentEXACountryPicker.section.preferredEXACountryPicker.section.currentLocation
Add translations in your app (recommended) in EXACountryPicker.strings:
"EXACountryPicker.section.recent" = "Récents";
"EXACountryPicker.section.preferred" = "Favoris";
"EXACountryPicker.section.currentLocation" = "Position actuelle";
Or override titles directly:
picker.theme.recentTitle = "Récents"
picker.theme.preferredTitle = "Favoris"
picker.theme.currentLocationTitle = "Position actuelle"


