In this tutorial, we’ll implement EditText in our Android Application. We’ll create EditText using XML as well as programmatically.
Android EditText
Android EditText is a subclass of TextView that allows user input and editing. It’s commonly used in login screens and forms.
EditText XML Definition
An EditText is defined in the XML in the following way.
<EditText
android:id="@+id/inNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="@string/enter_a_number_here"
android:imeOptions="actionNext"
android:inputType="number" />
EditText attributes
android:id
is used to set a unique identifier on the EditTextlayout_margin
is used to set the margin outside the EditText view.hint
is used to set the hint of the EditText.imeOptions
is used to set the behaviour of the bottom rightmost keyboard button. It can be set to done, search, next etc. Setting it to next would take the cursor to the next EditText present in the screen.inputType
is used to specify the input format allowed. By default it is text. email, number, numberDecimal etc can be set as per our needs.
Creating an EditText Programmatically
We have to create the EditText object and then add it to the screen layout.
val editText = EditText(this)
linearLayout.addView(editText)
EditText TextWatcher
TextWatcher is an interface, which listens to changes in the EditText before, after, and during an input is being typed.
It contains three functions that need to be overridden.
- afterTextChanged : it gets triggered immediately after something is typed
- beforeTextChanged : gets triggered before the next input.
- onTextChanged : it gets triggered during an input.
To set a TextWatcher on the EditText, we invoke the interface inside an addTextChangedListener
function.
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
toast(message = "Number is $s")
}
})
Kotlin Objects aren’t the same as the Java objects.
The onTextChanged() function differs from the afterTextChanged() in terms of the arguments.
Our example app would listen for changes in EditText input and update them in a TextView defined programmatically.
Android EditText Example Project Structure
1. Layout Code
The code for the activity_main.xml layout is given below.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/inNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="@string/enter_a_number_here"
android:imeOptions="actionNext"
android:inputType="number" />
</LinearLayout>
2. Activity code
The code for the MainActivity.kt class is given below:
package net.androidly.androidlyedittext
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.content.ContextCompat
import android.text.Editable
import android.text.TextWatcher
import android.view.inputmethod.EditorInfo
import android.widget.*
import kotlinx.android.synthetic.main.activity_main.*
import android.widget.LinearLayout
class MainActivity : AppCompatActivity() {
val txtAfter by lazy { TextView(this) }
val txtOn by lazy { TextView(this) }
val txtBefore by lazy { TextView(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val inNumber = findViewById(R.id.inNumber)
inNumber.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
toast(message = "Number is $s")
}
})
val editText = EditText(this)
editText.apply {
setText("Androidly EditText")
hint = "Keep entering"
val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
lp.setMargins(8, 8, 8, 8)
layoutParams = lp
imeOptions = EditorInfo.IME_ACTION_NEXT
setTextColor(ContextCompat.getColor(this@MainActivity, android.R.color.holo_purple))
smartTextWatcher(
on = { txtOn.apply { text = "onTextChanged: $it" } },
after = { txtAfter.apply { text = "smartTextWatcher: $it" } },
before = { txtBefore.apply { text = "beforeTextChanged: $it" } }
)
}
linearLayout.addView(editText)
val editText2 = EditText(this)
editText2.apply {
hint = "Enter something"
val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
lp.setMargins(8, 8, 8, 8)
layoutParams = lp
setBackgroundColor(ContextCompat.getColor(this@MainActivity, android.R.color.holo_green_dark))
imeOptions = EditorInfo.IME_ACTION_DONE
smartTextWatcher(
on = { txtOn.apply { text = "onTextChanged: $it" } },
after = { txtAfter.apply { text = "smartTextWatcher: $it" } },
before = { txtBefore.apply { text = "beforeTextChanged: $it" } }
)
}
linearLayout.addView(editText2)
txtAfter.text = "AfterTextChanged :"
txtAfter.setPadding(8, 8, 8, 8)
linearLayout.addView(txtAfter)
txtOn.text = "OnTextChanged :"
txtOn.setPadding(8, 8, 8, 8)
linearLayout.addView(txtOn)
txtBefore.text = "BeforeTextChanged :"
txtBefore.setPadding(8, 8, 8, 8)
linearLayout.addView(txtBefore)
}
fun Context.toast(context: Context = applicationContext, message: String, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(context, message, duration).show()
}
fun EditText.smartTextWatcher(on: (String) -> Unit, after: (String) -> Unit, before: (String) -> Unit) {
this.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
after.invoke(s.toString())
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
before.invoke(s.toString())
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
on.invoke(s.toString())
}
})
}
}
In the above code, we’ve created the TextViews programmatically and lazily using by lazy
.
It means that the instance of TextView would be created only when it gets invoked in the class.
The findViewById<EditText> is used to get the EditText from the XML.
We display a toast when the text in the EditText is changed. The toast function is an extension function in Kotlin.
The apply
lambda expression is used to set the attributes on the EditText without the need to invoke the instance every time.
To set the layout parameters programmatically, we do:
val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
lp.setMargins(8, 8, 8, 8)
layoutParams = lp
fun EditText.smartTextWatcher
is an Extension function created to shorten the verbose code of the TextWatcher interface by using lambda expressions.
For each of its arguments, we update the respective text views inside the lambda expressions.
Output: