After some numerous tests, including the use of the AppCompatEditText
API, I can say that @ChristianAbela solution was without a doubt the one that worked without problems in a scenario where the project should support Android versions starting from API 23 (Android Marshmallow).
In my case I should also make the field, EditText
, go back to normal (editText.keyListener != null
) as soon as the user returns focus to the field.
So, if you can't leave the EditText
locked but still need to present an ellipsis, then the following code strategy may be useful.
1 - Support class
First I build all the field status hackcode into a support class:
import android.text.method.KeyListener
import android.widget.EditText
/**
* The purpose of this class is to allow saving the status of the fields
* present in the "Search estimate" page.
*
* Thus, it is possible to use a business logic where the fields present
* on this page show, when there is large content, ellipsis indicating
* that the content is even larger.
*/
class FieldDataStatusHolder {
private var procedureFieldText: String = ""
private var procedureFieldKeyListener: KeyListener? = null
private var locationFieldText: String = ""
private var locationFieldKeyListener: KeyListener? = null
fun holdData(
unfocusedField: EditText,
procedureField: EditText
) {
if (unfocusedField == procedureField) {
procedureFieldText = unfocusedField.text.toString()
procedureFieldKeyListener = unfocusedField.keyListener
} else {
locationFieldText = unfocusedField.text.toString()
locationFieldKeyListener = unfocusedField.keyListener
}
/**
* This binding to null is necessary because this is the core of
* the hackcode. This makes the editable View (EditText or
* subclasses) no longer editable and so the ellipses appear at
* the end of the field.
*/
unfocusedField.keyListener = null
}
fun retrieveHoldenData(
focusedField: EditText,
procedureField: EditText
) {
if (focusedField == procedureField && procedureFieldKeyListener != null) {
focusedField.keyListener = procedureFieldKeyListener
if (focusedField.text.isNotEmpty()) {
focusedField.setText(procedureFieldText)
}
} else if (locationFieldKeyListener != null) {
focusedField.keyListener = locationFieldKeyListener
if (focusedField.text.isNotEmpty()) {
focusedField.setText(locationFieldText)
}
}
}
}
In the code above, don't be confused by properties and variables containing prefixes or suffixes like "Procedure" and "Location".
That's because these are labels referring to the problem domain I was applying the code to.
I had two fields on screen, "Search procedure" and "Search Location".
As soon as the user removes focus from one or both fields, if the field's content is longer than the field itself, then the ellipsis should appear at the end of the visual component.
2 - Hackcode instance declaration
In the client class I added the declaration lazily (but you can proceed as you wish) and in class scope and not in function scope:
private val fieldDataStatusHolder by lazy {
FieldDataStatusHolder()
}
3 - Execution on OnFocusChangeListener
So it was necessary to add the logical execution of the FieldDataStatusHolder
instance in the OnFocusChangeListener
generator method that I had already created:
private fun getFieldFocusChangeListener() = View.OnFocusChangeListener { view, hasFocus ->
// I do have lots of more domain code here.
if (hasFocus) {
fieldDataStatusHolder.retrieveHoldenData(
focusedField = view as EditText,
procedureField = etProcedureField
)
} else {
fieldDataStatusHolder.holdData(
unfocusedField = view as EditText,
procedureField = etProcedureField
)
}
}
This method is used as follows to initialize listeners on fields:
etProcedureField.onFocusChangeListener = getFieldFocusChangeListener()
etLocationField.onFocusChangeListener = getFieldFocusChangeListener()
4 - Views in XML
Finally, it was necessary to add the attributes and values below to the EditText
s:
android:ellipsize="end"
;
android:maxLines="1"
.
Note that even for Android 23 I didn't need the following attributes:
android:singleLine
(deprecated);
android:scrollHorizontally
.
Another important point is… I am actually using the following visual components for each field:
TextInputLayout
;
TextInputEditText
.
And the TextInputLayout
component contains an endIcon
. Therefore, every time the field loses focus, so that the ellipsis appears (Android API 31+), I also hide the endIcon
.
But that's an algorithm I won't add here to avoid making the answer even more verbose.
And yes, the code here should work not only for EditText
, but for any its subclass as well.
Results
Field with focus:

Field without focus:
