Format a number string into 2 decimal double independent of the number string length

1k Views Asked by At

In Android application developed using Kotlin, there have an EditText which accepts number only which is considered as USD. The input needs to be formatted into 2 decimals so that the input needs to be formatted as below

  • 7 -> 0.07
  • 73 -> 0.73
  • 736 -> 7.36

Tried using input filter. Input filter is also used to limit max value and single decimal input entry.

editTextField.filters =
            arrayOf(DecimalInputFilter())

class DecimalDigitsInputFilter() : InputFilter {
    override fun filter(
    source: CharSequence?,
    start: Int,
    end: Int,
    dest: Spanned?,
    dstart: Int,
    dend: Int
    ): CharSequence? {}

}

Couldn't manage to get the number formatted. Able to restrict inputs based on the rule.

editTextField.addTextChangedListener(object : TextWatcher{
   override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        print("beforeTextChanged")
  }

  override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
       print("onTextChanged")
       val inputFormatter = DecimalFormat("0.00")
       inputFormatter.isDecimalSeparatorAlwaysShown = true
       inputFormatter.minimumFractionDigits = 2
       editTextField.setText((s.toString()).format(inputFormatter))
  }

  override fun afterTextChanged(s: Editable?) {
       print("afterTextChanged")
  }
    
  })

This also fails.

2

There are 2 best solutions below

0
On BEST ANSWER

I think the main problem is that you are setting a text to the EditText inside of a TextWatcher which leads to looping recursion and then stack-overflow. You should change the text wrapped in removing and adding again the TextWatcher. Here is a simple solution:

editTextField.addTextChangedListener(object : TextWatcher {
    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        print("beforeTextChanged")
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        print("onTextChanged")

        val newValue = s.toString()
            .takeIf { it.isNotBlank() }
            ?.replace(".", "")
            ?.toDouble() ?: 0.0

        editTextField.let {
            it.removeTextChangedListener(this)
            it.setText(String.format("%.2f", newValue / 100))
            it.setSelection(it.text?.length ?: 0)
            it.addTextChangedListener(this)
        }
    }

    override fun afterTextChanged(s: Editable?) {
        print("afterTextChanged")
    }
})
0
On

For Kotlin

 fun roundOffDecimal(number: Double): String? {
        val df = DecimalFormat("#,###,###.##")
        df.roundingMode = RoundingMode.CEILING
        return df.format(number)
    }

RoundingMode.CEILNG or RoundingMode.FLOOR is used to round up the last digit.

#,###,###.##

customize this part according to the place value type you need and the number of decimal digits you want.

The above code will show the result something similar to 3,250,250.12