CountryPicker
One of the input fields to your app may be the country of a user, say in an app that registers users. In such a case you would need to define an array of countries then load them in a list, then handle click events for the clicked item. That's not difficult but what if you want to provide richer experience, let the countries have flags, provide a search capability etc? Well your code will add up. You can therefore consider using the following country picker libraries. They are lightweight and won't clatter up your app.
(a). Country-Picker
Android Library that can be used to show a country picker.
Here are its features:
- Written in Kotlin
- No boilerplate code
- Easy initialization
- Search countries
- Show country names alongside flags.
Step 1: Installing Country Picker
Start by registering jitpack as a maven url in your build.gradle as a repository:
Then specify the implementation statement in the dependencies closure:
Then sync the project.
Step 2: Write Kotlin Code
The next step is to write code.
You can find a country by name:
private fun findByName() {
countryPicker = CountryPicker.Builder().with(this@MainActivity)
.listener(this@MainActivity).build()
val builder = AlertDialog.Builder(this, R.style.Base_Theme_MaterialComponents_Dialog_Alert)
val input = EditText(this)
input.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
builder.setTitle("Country Name")
builder.setView(input)
builder.setCancelable(false)
builder.setPositiveButton(android.R.string.ok) { dialog, which ->
val country = countryPicker.getCountryByName(input.text.toString())
if (country == null) {
Toast.makeText(this@MainActivity, "Country not found", Toast.LENGTH_SHORT).show()
} else {
showResultActivity(country)
}
}
builder.setNegativeButton(android.R.string.cancel) { dialog, which -> dialog.cancel() }
builder.show()
}
Here's how to find a country by sim:
private fun findBySim() {
countryPicker = CountryPicker.Builder().with(this@MainActivity)
.listener(this@MainActivity).build()
val country = countryPicker.countryFromSIM
if (country == null) {
Toast.makeText(this@MainActivity, "Country not found", Toast.LENGTH_SHORT).show()
} else {
showResultActivity(country)
}
}
Here's how to find a country by locale:
private fun findByLocale() {
countryPicker = CountryPicker.Builder().with(this@MainActivity)
.listener(this@MainActivity).build()
val country = countryPicker.getCountryByLocale(Locale.getDefault())
if (country == null) {
Toast.makeText(this@MainActivity, "Country not found", Toast.LENGTH_SHORT).show()
} else {
showResultActivity(country)
}
}
Here's how to find a country by ISO:
private fun findByIson() {
countryPicker = CountryPicker.Builder().with(this@MainActivity)
.listener(this@MainActivity).build()
val builder = AlertDialog.Builder(this, R.style.Base_Theme_MaterialComponents_Dialog_Alert)
val input = EditText(this)
input.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
builder.setTitle("Country Code")
builder.setView(input)
builder.setCancelable(false)
builder.setPositiveButton(android.R.string.ok) { dialog, which ->
val country = countryPicker.getCountryByISO(input.text.toString())
if (country == null) {
Toast.makeText(this@MainActivity, "Country not found", Toast.LENGTH_SHORT).show()
} else {
showResultActivity(country)
}
}
builder.setNegativeButton(android.R.string.cancel) { dialog, which -> dialog.cancel() }
builder.show()
}
Example
Let's look at an example:
(a). MainActivity.kt
Heres the full code for main activity:
package com.limerse.picker
import android.content.Intent
import android.os.Bundle
import android.text.InputType
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SwitchCompat
import com.limerse.countrypicker.Country
import com.limerse.countrypicker.CountryPicker
import com.limerse.countrypicker.listeners.OnCountryPickerListener
import java.util.*
class MainActivity : AppCompatActivity(), OnCountryPickerListener {
private var pickCountryButton: Button? = null
private var findByNameButton: Button? = null
private var findBySimButton: Button? = null
private var findByLocaleButton: Button? = null
private var findByIsoButton: Button? = null
private lateinit var countryPicker: CountryPicker
private var themeSwitch: SwitchCompat? = null
private var styleSwitch: SwitchCompat? = null
private var useBottomSheet: SwitchCompat? = null
private var searchSwitch: SwitchCompat? = null
private var sortByRadioGroup: RadioGroup? = null
private var sortBy = CountryPicker.SORT_BY_NONE
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initialize()
setListener()
}
private fun setListener() {
findByNameButton!!.setOnClickListener { findByName() }
findBySimButton!!.setOnClickListener { findBySim() }
findByLocaleButton!!.setOnClickListener { findByLocale() }
findByIsoButton!!.setOnClickListener { findByIson() }
sortByRadioGroup!!.setOnCheckedChangeListener { radioGroup, id ->
sortBy = when (id) {
R.id.none_radio_button -> CountryPicker.SORT_BY_NONE
R.id.name_radio_button -> CountryPicker.SORT_BY_NAME
R.id.dial_code_radio_button -> CountryPicker.SORT_BY_DIAL_CODE
R.id.iso_radio_button -> CountryPicker.SORT_BY_ISO
else -> CountryPicker.SORT_BY_NONE
}
}
pickCountryButton!!.setOnClickListener { showPicker() }
}
private fun findByIson() {
countryPicker = CountryPicker.Builder().with(this@MainActivity)
.listener(this@MainActivity).build()
val builder = AlertDialog.Builder(this, R.style.Base_Theme_MaterialComponents_Dialog_Alert)
val input = EditText(this)
input.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
builder.setTitle("Country Code")
builder.setView(input)
builder.setCancelable(false)
builder.setPositiveButton(android.R.string.ok) { dialog, which ->
val country = countryPicker.getCountryByISO(input.text.toString())
if (country == null) {
Toast.makeText(this@MainActivity, "Country not found", Toast.LENGTH_SHORT).show()
} else {
showResultActivity(country)
}
}
builder.setNegativeButton(android.R.string.cancel) { dialog, which -> dialog.cancel() }
builder.show()
}
private fun findByLocale() {
countryPicker = CountryPicker.Builder().with(this@MainActivity)
.listener(this@MainActivity).build()
val country = countryPicker.getCountryByLocale(Locale.getDefault())
if (country == null) {
Toast.makeText(this@MainActivity, "Country not found", Toast.LENGTH_SHORT).show()
} else {
showResultActivity(country)
}
}
private fun findBySim() {
countryPicker = CountryPicker.Builder().with(this@MainActivity)
.listener(this@MainActivity).build()
val country = countryPicker.countryFromSIM
if (country == null) {
Toast.makeText(this@MainActivity, "Country not found", Toast.LENGTH_SHORT).show()
} else {
showResultActivity(country)
}
}
private fun findByName() {
countryPicker = CountryPicker.Builder().with(this@MainActivity)
.listener(this@MainActivity).build()
val builder = AlertDialog.Builder(this, R.style.Base_Theme_MaterialComponents_Dialog_Alert)
val input = EditText(this)
input.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
builder.setTitle("Country Name")
builder.setView(input)
builder.setCancelable(false)
builder.setPositiveButton(android.R.string.ok) { dialog, which ->
val country = countryPicker.getCountryByName(input.text.toString())
if (country == null) {
Toast.makeText(this@MainActivity, "Country not found", Toast.LENGTH_SHORT).show()
} else {
showResultActivity(country)
}
}
builder.setNegativeButton(android.R.string.cancel) { dialog, which -> dialog.cancel() }
builder.show()
}
private fun showResultActivity(country: Country?) {
val intent = Intent(this@MainActivity, ResultActivity::class.java)
intent.putExtra(ResultActivity.Companion.BUNDLE_KEY_COUNTRY_NAME, country!!.name)
intent.putExtra(ResultActivity.Companion.BUNDLE_KEY_COUNTRY_CURRENCY, country.currency)
intent.putExtra(ResultActivity.Companion.BUNDLE_KEY_COUNTRY_DIAL_CODE, country.dialCode)
intent.putExtra(ResultActivity.Companion.BUNDLE_KEY_COUNTRY_ISO, country.getCode())
intent.putExtra(ResultActivity.Companion.BUNDLE_KEY_COUNTRY_FLAG_IMAGE, country.flag)
startActivity(intent)
}
private fun showPicker() {
val builder = CountryPicker.Builder().with(this@MainActivity)
.listener(this@MainActivity)
if (styleSwitch!!.isChecked) {
builder.style(R.style.CountryPickerStyle)
}
builder.theme(if (themeSwitch!!.isChecked) CountryPicker.THEME_NEW else CountryPicker.THEME_OLD)
builder.canSearch(searchSwitch!!.isChecked)
builder.sortBy(sortBy)
countryPicker = builder.build()
if (useBottomSheet!!.isChecked) {
countryPicker.showBottomSheet(this@MainActivity)
} else {
countryPicker.showDialog(this@MainActivity)
}
}
private fun initialize() {
pickCountryButton = findViewById(R.id.country_picker_button)
themeSwitch = findViewById(R.id.theme_toggle_switch)
styleSwitch = findViewById(R.id.custom_style_toggle_switch)
useBottomSheet = findViewById(R.id.bottom_sheet_switch)
searchSwitch = findViewById(R.id.search_switch)
sortByRadioGroup = findViewById(R.id.sort_by_radio_group)
findByNameButton = findViewById(R.id.by_name_button)
findBySimButton = findViewById(R.id.by_sim_button)
findByLocaleButton = findViewById(R.id.by_local_button)
findByIsoButton = findViewById(R.id.by_iso_button)
}
override fun onSelectCountry(country: Country?) {
showResultActivity(country)
}
}
(b). ResultActivity.kt
Here's the result activity:
package com.limerse.picker
import android.os.Bundle
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class ResultActivity : AppCompatActivity() {
private var countryNameTextView: TextView? = null
private var countryIsoCodeTextView: TextView? = null
private var countryDialCodeTextView: TextView? = null
private var selectedCountryCurrency: TextView? = null
private var countryFlagImageView: ImageView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result)
initialize()
showData()
}
private fun showData() {
val bundle = intent.extras
if (bundle != null) {
countryNameTextView!!.text = bundle.getString(BUNDLE_KEY_COUNTRY_NAME)
countryIsoCodeTextView!!.text = bundle.getString(BUNDLE_KEY_COUNTRY_ISO)
countryDialCodeTextView!!.text = bundle.getString(BUNDLE_KEY_COUNTRY_DIAL_CODE)
selectedCountryCurrency!!.text = bundle.getString(BUNDLE_KEY_COUNTRY_CURRENCY)
countryFlagImageView!!.setImageResource(bundle.getInt(BUNDLE_KEY_COUNTRY_FLAG_IMAGE))
}
}
private fun initialize() {
countryNameTextView = findViewById(R.id.selected_country_name_text_view)
countryIsoCodeTextView = findViewById(R.id.selected_country_iso_text_view)
countryDialCodeTextView = findViewById(R.id.selected_country_dial_code_text_view)
countryFlagImageView = findViewById(R.id.selected_country_flag_image_view)
selectedCountryCurrency = findViewById(R.id.selected_country_currency)
val backButton = findViewById<ImageButton>(R.id.back_button)
backButton.setOnClickListener { finish() }
}
companion object {
const val BUNDLE_KEY_COUNTRY_NAME = "country_name"
const val BUNDLE_KEY_COUNTRY_ISO = "country_iso"
const val BUNDLE_KEY_COUNTRY_DIAL_CODE = "dial_code"
const val BUNDLE_KEY_COUNTRY_CURRENCY = "currency"
const val BUNDLE_KEY_COUNTRY_FLAG_IMAGE = "flag_image"
}
}
You can find the layouts here
Reference
Find reference here