Trying to learn kotlin and I'm working on a simple conversion app where I have two edittexts. I would like for the calculation to happen automatically when I change the text. So if edittext2 is supposed to be 10 times larger than edittext1, I'd like edittext1 change to 10 if I enter 100 in edittext2 and if I change edittext2 to 50, edittext1 changes to 5, etc..
Currently I have a convert and clear button, but I would like to minimize the design and make it less cumbersome.
Try this out
edittext2.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int,
count: Int) {
if (s != "") {
val outPut=Integer.parseInt("get the value of editText1")+ Integer.parseInt("get the value of editText2")
txtOutPut.text="$outPut"
}
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int,
after: Int) {
}
override fun afterTextChanged(s: Editable) {
}
})
Related
I have an EditText object with the numberDecimal input type. The input manipulation (e.g., calculation) is working ok, but inputs starting with "00" and "0123-like" (zero followed by a number, not the dot) are currently permitted.
How can I forbid inputs starting with "00" or "0123-like" (zero followed by a number, not the dot), in Kotlin?
Aftering googling and reading many similar questions and answers, I've tried TextWatcher and InputFilter, but can't really figure out a solution.
You can use a TextWatcher and regular expression if the modified string is in the format 0, followed by a number, you can remove the last inserted digit and return to a string containing only the initial 0.
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
val newText = s.toString().trim()
// Check if the text is 0 followed by another digit, in that case remove the last inserted value
if (newText.length > 1 && newText.matches("^0[\\d]+".toRegex())) {
// Unwanted expression: remove last inserted char and reset the cursor position to show after the first character
editText.setText("0")
editText.setSelection(1)
}
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})
EDIT
If you need to apply the same TextWatcher to multiple EditText you could define your CustomTextWatcher class:
class CustomTextWatcher(
private val editText: EditText
) : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
val newText = s.toString().trim()
// Check if the text is 0 followed by another digit, in that case remove the last inserted value
if (newText.length > 1 && newText.matches("^0[\\d]+".toRegex())) {
// Unwanted expression: remove last inserted char and reset the cursor position to show after the first character
editText.setText("0")
editText.setSelection(1)
}
}
}
And then add it to your EditTexts with:
editText1.addTextChangedListener(CustomTextWatcher(editText1));
editText2.addTextChangedListener(CustomTextWatcher(editText2));
...
I am working on EditText where I am displaying pre filled country code in start lets say "+971", what I want is that if user trying to click and edit in EditText, he should not edit or delete "+971" and can only be able to put number after that like "+971 123445579" and if trying to delete number then "+971" should not get delete.
My code is given below, please guide me how can I achieve this. Thanks
private fun setupTextChangeListener() {
edit_text.textWatcherListener = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
setDatePickerIconOnDemand()
}
override fun afterTextChanged(s: Editable?) {
}
}
}
// In this method I am putting Start Drawable in EditText:
private fun setDatePickerIconOnDemand() {
edit_text.setDrawableStart(context.drawable(R.drawable.ic_earh_arrow_down_default))
edit_text.setDrawable()
}
You can add following lines of code in on onTextChanged callback
if (edit_text.length() < 5 || !edit_text.text!!.startsWith("+971 ")) {
edit_text.setText("+971 ")
edit_text.setSelection(edit_text.length())
}
What it will do is: It will check onTextChanged 'if your current text in edit text is only your country code, Set the country code in your editText and move cursor at the end.
I'm currently learning android in Kotlin, and I'm trying to create a tip calculator. I have two EditText views, one for the bill amount and tip amount. I also have two TextViews, one for the tip amount and one for the total + tip.
This is part of my code, where I am trying to have the EditText automatically update the TextViews upon user input.
billInput.addTextChangedListener(object: TextWatcher) {
override fun afterTextChanged(s: Editable) {
totalAmt.text = billInput + tipInput
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
}
For now, I am trying to have the bill + tip amount be added and update the TextView. I got the error "Expecting a class body" next to the first line. Am I using addTextChangedListener incorrectly or is something wrong with my code? I know there are probably more efficient ways to do this, but I was assuming I could just use addTextChangedListener for both EditText views. So, to clear things up: I want to input my bill amount and tip amount, and automatically update "Tip amount:" and "Total:" .
Edit*** : Would it make sense to do the numeric calculations (tip and total amount) under onTextChanged? That way as the input is received, the calculations are processed and afterTextChanged is responsible for displaying the final results?
You are adding EditText + EditText, should add values instead
billInput.addTextChangedListener(object: TextWatcher) {
override fun afterTextChanged(s: Editable) {
totalAmt.text = "${billInput.text.toString().toInt() + tipInput.text.toString().toInt()}"
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
}
Hello my friend you can set addTextChangedListener for both EditTexts and put same code for both of them because one person cant simultaneously type in both EditTexts.
do the code like below.
bill Input Edittext
billInput!!.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable) {
//code after changed
val bill = editable.toString().toInt()
val tip = tipInput!!.text.toString().toInt()
total.text = ((bill + tip).toString())
}
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
//code before text change
}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
//code during change
}
})
tip Input EditText
tipInput!!.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable) {
//code after changed
val bill = editable.toString().toInt()
val tip = billInput!!.text.toString().toInt()
total.text = ((bill + tip).toString())
}
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
//code before text change
}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
//code during change
}
})
I have an EditText with some pre-existing text that MUST NOT be deleted. The user should only be allowed to append text in the view.
The solution I have right now can be seen below, where I check if the new length of the EditText is shorter than the original text. If it is, the user has attempted to delete a character so I just repopulate the view with the original text and move the cursor. The problem with this solution is that the user could just enter text that is longer than the original length, then change the position of the cursor to somewhere within the original text, and finally delete characters.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val originalText = "Hello"
binding.et.setText(originalText)
binding.et.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
s?.let {
if (s.length < originalText.length) {
binding.et.setText(originalText)
binding.et.setSelection(originalText.count())
}
}
}
override fun afterTextChanged(s: Editable?) {}
})
}
What should I do? I'm open to all ideas.
Thanks!
Edit:
I've also tried combining an EditText and a TextView (as some have suggested) but the layout is difficult to achieve because both the original text and the new text can span multiple lines. My solution above contains one word in the original text but it could be many. So I need to cater for this scenario:
...where the white box represents the TextView and the red box represents the EditText.
I don't think Bö macht Blau's answer will work either because the prefix is in its own "column".
I think I will have to use Zain's solution with (startsWith()) or create a custom view (though I've never done one of these before).
Please consider #Gabe Sechan advice in OP comments that the EditText alone is not the optimum solution for that.
In case you still need to use EditText then you can change the condition to check that the returned CharSequence of the EditText watcher starts with the original text using startsWith() method
et.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
s?.let {
if (!s.startsWith(originalText)) {
if (s.length <= originalText.length) {
et.setText(originalText)
et.setSelection(originalText.count())
} else {
et.setText(originalText + s.subSequence(originalText.length, s.length))
et.setSelection(s.count())
}
}
}
}
override fun afterTextChanged(s: Editable?) {}
})
You can use a text field, that's a combination of a TextInputEditText and a TextInputLayout. Then you can set a prefix like so:
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:prefixText="#string/prefix_text">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout>
The prefix will be visible as soon as the TextInputEditText gains focus. Since it is not part of the EditText content, it can't be modified by the users.
Useful links:
documentation for TextInputLayout
overview of style options
This check should work:
if (s.substring(0, 4) == originalText) {
// update text
}
But consider looking into InputFilter, as a comment suggested.
I am using a tag system similar to SO, and instead of forcing the user to find the dash in their keyboard I want space to automatically be translated to a dash.
I am trying to implement it with this textWatcher, but the app doesn't let me type the space bar (it kinda flashes but nothing happens.
imageTagsInput.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
imageTagsInput.removeTextChangedListener(this)
imageTagsInput.setText(imageTagsInput.text.toString().replace(" ","-"))
imageTagsInput.addTextChangedListener(this)
imageTagsInput.setSelection(imageTagsInput.length())
}
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
})
And this is the xml of the EditText:
android:digits="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789- "
Add something like this in afterTextChanged
String result = s.toString().replaceAll(" ", "-");
if (!s.toString().equals(result)) {
ed.setText(result);
ed.setSelection(result.length());
// alert the user
}
For more info see this answer