Having trouble using addTextChangeListener & updating values? - android

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
}
})

Related

How to forbid "00" or "0123-like" start of input in Android EditText, in Kotlin?

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));
...

How to get full text from the editText by using addTextChangedListener in kotlin

I would like to add full text from the editText into an array. But while running this code the array
values will be like first word , second word etc. How to get the full sentence and i want to add it
into an array(Already did it using interface)
Note : The code is placed on the recyclerview adapter ,
Where texBox is the EditText and examinationListener is the interface used
Here i shared the code. Please check it.
textBox.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
textFromBox = s.toString()
examinationListener.addAnswer(textFromBox)
}
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) {
textFromBox = textBox.text.toString()
examinationListener.addAnswer(textFromBox)
}
I created an array up to the list size. Each items of RecyclerView have an EditText.
val array = arrayOfNulls<String>(listSize)
We need to know the position of EditText to add to the array. Change interface like this:
interface ExaminationListener {
fun addAnswer(text: String, position: Int)
}
function addAnswer:
override fun addAnswer(text: String, position: Int) {
array[position] = text // we add every changes to the array.
}
This use is more useful. We don't need other methods:
textBox.doAfterTextChanged {
examinationListener.addAnswer(it.toString(), position) // you can use adapterPosition if that is in Viewholder
}
We create a sentence from array elements. You can see your full sentence:
val sentence = array.filterNotNull().joinToString (separator = " ") { it -> it }
Log.d("Sentence" , sentence)
Very Simple just add a TextWatcher to your EditText like:
val answerWatcher = object : TextWatcher {
override fun beforeTextChanged(value: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(value: CharSequence, start: Int, before: Int, count: Int) {
when {
// Here value is your full text from your EditText
value.toString().equals("I am a sentence", ignoreCase = true) -> {
}
else -> {
// Just a test condition
}
}
}
override fun afterTextChanged(s: Editable) {
}
}
// Add this TextWatcher to your EditText
edittext.addTextChangedListener(answerWatcher)

Updating EditTexts on the fly

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) {
}
})

How can I replace one note with a different note as the user is typing (replace “space” with “-”

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

Kotlin addTextChangeListener lambda?

How do you build a lambda expression for the EditText addTextChangeListener in Kotlin? Below gives an error:
passwordEditText.addTextChangedListener { charSequence ->
try {
password = charSequence.toString()
} catch (error: Throwable) {
raise(error)
}
}
addTextChangedListener() takes a TextWatcher which is an interface with 3 methods. What you wrote would only work if TextWatcher had only 1 method. I'm going to guess the error you're getting relates to your lambda not implementing the other 2 methods. You have 2 options going forward.
Ditch the lambda and just use an anonymous inner class
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
Create an extension method so you can use a lambda expression:
fun EditText.afterTextChanged(afterTextChanged: (String) -> Unit) {
this.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) {
}
override fun afterTextChanged(editable: Editable?) {
afterTextChanged.invoke(editable.toString())
}
})
}
And then use the extension like so:
editText.afterTextChanged { doSomethingWithText(it) }
Add this core ktx dependence
implementation 'androidx.core:core-ktx:1.0.0'
You simply have to do
passwordEditText.doAfterTextChanged{ }
A bit old, but using Kotlin Android extensions you can do something like that:
editTextRequest.textChangedListener {
afterTextChanged {
// Do something here...
}
}
No extra code needed, just add:
implementation 'androidx.core:core-ktx:1.0.0'
Sorry for being late!
If you add implementation 'androidx.core:core-ktx:1.1.0' to your module's build.gradle file then you can use
etPlayer1.doOnTextChanged { text, start, count, after -> // Do stuff }
Test it :
passwordEditText.addTextChangedListener(object:TextWatcher{
override fun afterTextChanged(s: Editable?) { }
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { }
})
hope this Kotlin sample help making it clear:
class MainFragment : Fragment() {
private lateinit var viewModel: MainViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
val view = inflater.inflate(R.layout.main_fragment, container, false)
view.user.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) {
}
override fun afterTextChanged(s: Editable) {
userLayout.error =
if (s.length > userLayout.counterMaxLength) {
"Max character length is: ${userLayout.counterMaxLength}"
} else null
}
})
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
// TODO: Use the ViewModel
}
}
With this XML layout:
<android.support.design.widget.TextInputLayout
android:id="#+id/userLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:counterMaxLength="5"
app:counterEnabled="true"
android:hint="user_name">
<android.support.design.widget.TextInputEditText
android:id="#+id/user"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout>
And this Gradle:
android {
compileSdkVersion 'android-P'
...
}
api 'com.android.support:design:28.0.0-alpha1'
implementation 'com.android.support:appcompat-v7:28.0.0-alpha1' // appcompat library
In case you're using Material Filled text field or Outlined text field, attempt to respond to input text change as mentioned by documentation, respectively:
filledTextField.editText?.doOnTextChanged { inputText, _, _, _ ->
// Respond to input text change
}
and
outlinedTextField.editText?.doOnTextChanged { inputText, _, _, _ ->
// Respond to input text change
}
if you use implementation 'androidx.core:core-ktx:1.1.0-alpha05' you can use
For android.widget.TextView
TextWatcher
TextView.doBeforeTextChanged(crossinline action: (text: CharSequence?, start: Int, count: Int, after: Int) -> Unit)
Add an action which will be invoked before the text changed.
TextWatcher
TextView.doOnTextChanged(crossinline action: (text: CharSequence?, start: Int, count: Int, after: Int) -> Unit)
Add an action which will be invoked when the text is changing.
TextWatcher
TextView.doAfterTextChanged(crossinline action: (text: Editable?) -> Unit)
https://developer.android.com/reference/kotlin/androidx/core/widget/package-summary#extension-functions
Add the core ktx dependency
implementation 'androidx.core:core-ktx:1.3.0'
And you can simply implement like this
edit_text.addTextChangedListener { it: Editable? ->
// Do your stuff here
}
Another alternative is the KAndroid library -
implementation 'com.pawegio.kandroid:kandroid:0.8.7#aar'
Then you could do something like this...
editText.textWatcher { afterTextChanged { doSomething() } }
Obviously it is excessive to use an entire library to solve your problem, but it also comes with a range of other useful extensions that eliminate boilerplate code in the Android SDK.
You can make use of kotlin's named parameters:
private val beforeTextChangedStub: (CharSequence, Int, Int, Int) -> Unit = { _, _, _, _ -> }
private val onTextChangedStub: (CharSequence, Int, Int, Int) -> Unit = { _, _, _, _ -> }
private val afterTextChangedStub: (Editable) -> Unit = {}
fun EditText.addChangedListener(
beforeTextChanged: (CharSequence, Int, Int, Int) -> Unit = beforeTextChangedStub,
onTextChanged: (CharSequence, Int, Int, Int) -> Unit = onTextChangedStub,
afterTextChanged: (Editable) -> Unit = afterTextChangedStub
) = addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
beforeTextChanged(charSequence, i, i1, i2)
}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
onTextChanged(charSequence, i, i1, i2)
}
override fun afterTextChanged(editable: Editable) {
afterTextChanged(editable)
}
})
This is the lambda function with edit text field with TextWatcher
searchField.addTextChangedListener(
afterTextChanged = {
},
onTextChanged = {s, start, before, count->
TODO("DO your code")
},
beforeTextChanged = {s, start, before, count->
TODO("DO your code")
}
)
This looks neat:
passwordEditText.setOnEditorActionListener {
textView, keyCode, keyEvent ->
val DONE = 6
if (keyCode == DONE) {
// your code here
}
false
}

Categories

Resources