PCSalt
YouTube GitHub
Back to Kotlin
Kotlin · 2 min read

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 visibility
  • sharedPreferences.edit { putString("key", "value") } — commit-free editing
  • bundleOf("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.