5 Kotlin Extension Functions You'll Use in Every Android Project
Practical Kotlin extension functions for Android — view visibility, toasts, keyboard handling, dp conversion, and intent helpers. Copy, paste, use.
Extension functions are one of Kotlin’s best features. They let you add methods to existing classes without inheritance or wrappers. For Android, this means cleaner code with less boilerplate.
Here are 5 extension functions I use in every project. Each one replaces something ugly with something readable.
1. View Visibility — show(), hide(), gone()
Every Android project has this pattern scattered everywhere:
if (isLoading) {
progressBar.visibility = View.VISIBLE
content.visibility = View.GONE
} else {
progressBar.visibility = View.GONE
content.visibility = View.VISIBLE
}
View.VISIBLE, View.GONE, View.INVISIBLE — verbose and easy to mix up. Fix it once:
import android.view.View
fun View.show() {
visibility = View.VISIBLE
}
fun View.hide() {
visibility = View.INVISIBLE
}
fun View.gone() {
visibility = View.GONE
}
fun View.showIf(condition: Boolean) {
visibility = if (condition) View.VISIBLE else View.GONE
}
Now the same code reads like English:
if (isLoading) {
progressBar.show()
content.gone()
} else {
progressBar.gone()
content.show()
}
// Or even simpler
progressBar.showIf(isLoading)
content.showIf(!isLoading)
hide() keeps the view’s space in the layout (INVISIBLE). gone() removes it from layout flow (GONE). Name them what they do, not what constant they set.
2. Toast and Snackbar — Without the Ceremony
The standard Toast API:
Toast.makeText(this, "Item saved", Toast.LENGTH_SHORT).show()
Every time. makeText, context, message, duration, .show(). Five things to remember for a one-line message. And if you forget .show(), nothing happens — no error, no toast, just silence.
import android.content.Context
import android.widget.Toast
import com.google.android.material.snackbar.Snackbar
fun Context.toast(message: String, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, duration).show()
}
fun Context.toastLong(message: String) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
fun android.view.View.snackbar(
message: String,
duration: Int = Snackbar.LENGTH_SHORT,
actionText: String? = null,
action: (() -> Unit)? = null
) {
val snackbar = Snackbar.make(this, message, duration)
if (actionText != null && action != null) {
snackbar.setAction(actionText) { action() }
}
snackbar.show()
}
Usage:
// In an Activity or Fragment
toast("Item saved")
toastLong("This will take a moment...")
// Snackbar with action
binding.root.snackbar(
"Item deleted",
actionText = "Undo",
action = { restoreItem() }
)
The snackbar extension is on View (not Context) because Snackbar needs a view to anchor to. Pass the root view or any view in the layout.
3. EditText — IME Done Action Without the Boilerplate
Handling the “Done” button on the keyboard requires this:
editText.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
submitForm()
true
} else {
false
}
}
Every. Single. Time. The EditorInfo import, the action ID check, the boolean return. Wrap it:
import android.view.inputmethod.EditorInfo
import android.widget.EditText
fun EditText.onDone(action: () -> Unit) {
setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
action()
true
} else {
false
}
}
}
fun EditText.onAction(imeAction: Int, action: () -> Unit) {
setOnEditorActionListener { _, actionId, _ ->
if (actionId == imeAction) {
action()
true
} else {
false
}
}
}
val EditText.trimmedText: String
get() = text.toString().trim()
Usage:
binding.etSearch.onDone {
performSearch(binding.etSearch.trimmedText)
}
// Or for other IME actions
binding.etNext.onAction(EditorInfo.IME_ACTION_NEXT) {
binding.etPassword.requestFocus()
}
trimmedText is an extension property — saves you from writing .text.toString().trim() everywhere. Small thing, but you type it dozens of times in a project.
4. dp to px Conversion — Clean Programmatic Layouts
When building views in code or setting margins programmatically, Android wants pixel values. But you think in dp. The conversion formula is:
val pixels = (dp * resources.displayMetrics.density + 0.5f).toInt()
Nobody remembers this. And resources.displayMetrics.density is too long to type inline. Fix it:
import android.content.Context
import android.content.res.Resources
val Int.dp: Int
get() = (this * Resources.getSystem().displayMetrics.density + 0.5f).toInt()
val Float.dp: Float
get() = this * Resources.getSystem().displayMetrics.density
val Int.px: Float
get() = this / Resources.getSystem().displayMetrics.density
Usage:
// Set 16dp margin programmatically
val params = view.layoutParams as ViewGroup.MarginLayoutParams
params.setMargins(16.dp, 8.dp, 16.dp, 8.dp)
view.layoutParams = params
// Set 24dp padding
view.setPadding(24.dp, 12.dp, 24.dp, 12.dp)
// Convert pixels back to dp (useful for logging/debugging)
val dpValue = pixelValue.px
Resources.getSystem() works without a Context — it uses the system’s display metrics. This means you can use 16.dp anywhere, even in utility classes or data layers that don’t have access to a Context.
5. Intent Helpers — Open URLs, Share Text, Send Email
Every app opens URLs, shares text, or sends emails. The Intent API for these is verbose and error-prone:
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
// no browser installed?
}
Wrap the common patterns:
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
fun Context.openUrl(url: String) {
try {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
} catch (e: ActivityNotFoundException) {
// No app can handle this URL
}
}
fun Context.shareText(text: String, title: String = "Share via") {
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, text)
}
startActivity(Intent.createChooser(intent, title))
}
fun Context.sendEmail(
to: String,
subject: String = "",
body: String = ""
) {
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:")
putExtra(Intent.EXTRA_EMAIL, arrayOf(to))
putExtra(Intent.EXTRA_SUBJECT, subject)
putExtra(Intent.EXTRA_TEXT, body)
}
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
// No email app installed
}
}
fun Context.dialPhone(number: String) {
val intent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:$number"))
startActivity(intent)
}
Usage:
// In Activity or Fragment
openUrl("https://pcsalt.com")
shareText("Check out this article: https://pcsalt.com/kotlin/kotlin-extension-functions-android/")
sendEmail(
to = "[email protected]",
subject = "Question about your blog",
body = "Hey, I have a question..."
)
dialPhone("+91XXXXXXXXXX")
ACTION_DIAL opens the dialer with the number pre-filled (doesn’t make the call). ACTION_SENDTO with mailto: ensures only email apps handle the intent, not every app that can handle text.
Putting It All Together
Create a file called Extensions.kt (or split into ViewExtensions.kt, ContextExtensions.kt, etc. if you prefer) and drop these in:
// ViewExtensions.kt
fun View.show() { visibility = View.VISIBLE }
fun View.hide() { visibility = View.INVISIBLE }
fun View.gone() { visibility = View.GONE }
fun View.showIf(condition: Boolean) { visibility = if (condition) View.VISIBLE else View.GONE }
// ContextExtensions.kt
fun Context.toast(message: String, duration: Int = Toast.LENGTH_SHORT) { Toast.makeText(this, message, duration).show() }
fun Context.openUrl(url: String) { /* ... */ }
fun Context.shareText(text: String, title: String = "Share via") { /* ... */ }
// EditTextExtensions.kt
fun EditText.onDone(action: () -> Unit) { /* ... */ }
val EditText.trimmedText: String get() = text.toString().trim()
// DimensionExtensions.kt
val Int.dp: Int get() = (this * Resources.getSystem().displayMetrics.density + 0.5f).toInt()
Copy them into your next project. You’ll use all five within the first hour.
What About core-ktx?
Google’s core-ktx library already provides some Kotlin extensions for Android. For example:
view.isVisible = true— toggles visibilitysharedPreferences.edit { putString("key", "value") }— commit-free editingbundleOf("key" to "value")— cleaner Bundle creation
If core-ktx covers your need, use it — no point reinventing. The extensions in this post fill the gaps that core-ktx doesn’t cover, like onDone, toast, dp conversion, and intent helpers.