As was said in the question comments, to do this you would have to measure the size of each character entered in EditText
, and this is not as difficult as it seems.
I made it in Kotlin
, since since I'm using it in my projects, it would be faster and easier. The conversion to Java
will also be available right below.
First, and most importantly, we should know what size the EditText
is on the device screen, you can do this measurement using the OnGlobalLayoutListener , because it expects the view to be rendered and then you will have the correct size of it in pixels >. If you try to access the size directly, the returned value will be 0 .
This returns zero
int inputSize = ((EditText) findViewById(R.id.inputExample)).getWidth();
This returns the width of the component
((EditText) findViewById(R.id.inputExample)).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
inputSize = ((EditText) findViewById(R.id.inputExample)).getWidth();
}
});
The same goes for the Kotlin language, you will also have to use the same method above, but the code can get a bit more beautiful with some language implementations,
// https://antonioleiva.com/kotlin-ongloballayoutlistener/
inline fun <T: View> T.waitForMeasure(crossinline measure: T.() -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (measuredWidth > 0 && measuredHeight > 0) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
measure()
}
}
})
}
// .. MainActivity()
inputExample.waitForMeasure { // inputExample = é uma bind pra view com o kotlin-android-extensions
inputWidth = inputExample.measuredWidth
println("Edittext width (PX) is: $inputWidth")
}
Okay, now we have the size that the component is occupying on the device screen, in the example above, I tested on a Nexus 5X 1080x1920 and the value returned was 1080
. >
So, we can go to the second part, which is to calculate the space that the inserted character occupies on the screen. To do this, we have to use the Paint element of the component itself to measure the character with the method Paint # MeasureText (String) .
Java
int inputWidth = 0
float inputSize = 0.0
int maxCharCount = 0
// O tamanho do EditText primeiro :)
((EditText) findViewById(R.id.inputExample)).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
inputSize = ((EditText) findViewById(R.id.inputExample)).getWidth();
}
});
// A brincadeira começa aqui
((EditText) findViewById(R.id.inputExample)).addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence input, int start, int before, int count) {
Paint paint = inputExample.getPaint() // EditText ID: inputExample...
inputSize = paint.measureText(input.toString())
if (!TextUtils.isEmpty(inputExample.getText().toString())) {
// Pegar último caractere inserido
Char char = input[input.length - 1]
// Pega o espaço restante no EditText
// Isso depende do tamanho da EditText e do tamanho do TEXTO dela, em pixels.
// Ex: texto www = 90.0 (w = 30.0) | tela = 1080
// Espaço restante = 1080-90 = 990
float spaceLeft = (float) inputWidth - inputSize
// Pega o tamanho que a letra atual ocupa
// Ex: letra w = 30.0 ou a = 26
// Letras maiúsculas e minúsculas diferenciam-se em tamanhos
// w = 30 | W = 35
float charSpace = (float) paint.measureText(char.toString())
if (spaceLeft < charSpace * 1.75) {
println("no space left")
if (input.length() != maxCharCount) {
maxCharCount = input.length()
}
} else {
println("hm, there's some space")
int charCount = (int) spaceLeft / charSpace
maxCharCount = input.length
maxCharCount += charCount - (charCount - 1)
}
println("Space left: " + spaceLeft)
println("length: " + maxCharCount)
// Altera o limite da view de acordo com o espaço restante + tamanho do ultimo caractere inserido (ou o que ainda vai ser inserido)
// Se tiver espaço: o caractere consegue ser inserido
inputExample.setFilters(new InputFilter[] { new InputFilter.LengthFilter(maxCharCount) } );
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
Kotlin
var inputWidth: Int = 0
var inputSize: Float
var maxCharCount: Int = 0
inputExample.waitForMeasure {
inputWidth = inputExample.measuredWidth
println("Edittext width (PX) is: $inputWidth")
}
val listener = object : TextWatcher {
override fun afterTextChanged(input: Editable?) {}
override fun beforeTextChanged(input: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(input: CharSequence?, start: Int, before: Int, count: Int) {
val paint = inputExample.paint
inputSize = paint.measureText(input.toString())
if (input!!.isNotEmpty()) {
val char = input[input.length - 1]
val spaceLeft = inputWidth - inputSize
val charSpace = paint.measureText(char.toString())
if (spaceLeft < charSpace * 1.75) {
println("no space left")
println("Max char count: $maxCharCount")
if (input.length != maxCharCount) {
maxCharCount = input.length
}
} else {
println("hm, there's some space")
val charCount = (spaceLeft / charSpace).toInt()
maxCharCount = input.length
maxCharCount += charCount - (charCount - 1)
}
println("Space left: $spaceLeft")
println("length: $maxCharCount")
inputExample.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(maxCharCount))
}
}
}
inputExample.addTextChangedListener(listener)
Demo
Notes
- The code was initially made in Kotlin, not Java. So any errors you find, feel free to correct / add a comment.
- In Kotlin, I used the reference to the EditText component using Kotlin-android-extensions, where I do not need to be using findViewById .