As stated in the comments of the question, to do this you would have to measure the size of each character inserted in the EditText
, and it’s not as hard as it looks.
I did in Kotlin
, because since I am using it in my projects, it would be faster and easier. The conversion to Java
will also be available just below.
First, and most importantly, we should know how big the EditText
present on the device screen, you can make this measurement using the method Ongloballayoutlistener, because he hopes that the view be rendered and then you will have the correct size of it, in pixels. If you try to access its 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 language Kotlin, you will also have to use the same method above, but the code can get a little more beautiful with some language implementations such as:
// 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")
}
Ready, 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
.
Thus, 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 class Paint 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)
Demonstration
Remarks
- The code was initially made in Kotlin, not Java. So, any mistakes you encounter, feel free to correct/add a comment.
- In Kotlin, I used the component reference Edittext using Kotlin-android-Extensions, where I don’t need to be using findViewById.
I was intrigued, why do you want to do this, rs?
– Márcio Oliveira
Anyway, my guess would be to use a font with equal spacing between all characters, make a Asure in Edittext to pick the width in pixels and calculate the amount of characters that would fit in that space by the width of the same pixels.
– Márcio Oliveira
@Márciooliveira the question was really curious to see how many ways it would be possible to do this.
– viana
Because I think the biggest difficulty to do with the native font is that each character has its own spacing and you can’t predict what the user will type, so you would have to do the same calculation that I just suggested using a broad character, ex "O".
– Márcio Oliveira