What's syntax object : interface in Kotlin? - android

I'm newbie in Kotlin and Android.
I confused when see syntax when use TextWatcher like this:
editTextSample.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) {
txtView1.setText("Text in EditText : "+s)
}
})
Can you explain it for me. Thank you

EditText class extends TextView class which contains a method called addTextChangedListener().
Here you are creating the object of EditText class and calling that method. Where you need to pass the object of TextWatcher interface as argument.
[Hold on.. but we can not create the object of interface. So here we are
using concept of anonymous class for that, check this ].
and as the interface contains three methods we have to override them all. That's it.

Notation object : TextWatcher is just creating an anonymous class here. It's just kotlin way of creating it. Kotlin gives you more methods to implement TextWatchers.
You can import androidx.core:core-ktx dependency which provides a lot of nice features. One of them is extensions for textwatchers. With using this you can simplify your code to:
editTExt.doOnTextChanged { text, start, count, after ->
//Do something here
}

Related

What is the proper way to use EditText content change listener?

Am trying to do something when my EditText content is changed.
Here is 3 ways i find to do it.
1.
edittext.addTextChangedListener {
//my code
}
edittext.doAfterTextChanged {
//my code
}
edittext.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
//my code
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
})
All works perfectly for my purpose. Can somebody explain if there is any difference between each of them, any advantage or disadvantage using a particular way or simply all of them same?
1 and 3 are basically same thing. In kotling object : TextWatcher is not needed as it can wrap the implementation with lambda using just {}
edittext.addTextChangedListener {
//my code
}
What you did in the 3 with object : TextWatcher is same thing but the implemented functions afterTextChanged, beforeTextChanged and onTextChanged are visible.
And for 2, android in kotlin gives an inline function edittext.doAfterTextChanged which just does everything for you what you did on 3 using object : TextWatcher under the hood and gives access to only afterTextChanged functions implementation. This code is from androidx.core.widget package which shows what it's doing under the hood:
inline fun TextView.doAfterTextChanged(
crossinline action: (text: Editable?) -> Unit
) = addTextChangedListener(afterTextChanged = action)

How to use Inverse Binding Adapter in Kotlin for converting Lowercase text to Uppercase?

I am creating an android application where I want to use a feature in which a text that we have entered into an editText field can be converted into uppercase at runtime in that particular editText field only.
I have tried with this code
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) {
this.text.toString().uppercase()
}
})
But it can be easily done by the concept of Inverse Binding Adapter in android. I have tried to implement it with reference of
https://developer.android.com/reference/android/databinding/InverseBindingAdapter
It is not working for me in my project. Can You explain me with step by step explanation?
Yess This Method of addTextChangedListener is available but we have to implement this method for each and every Edittext we want to convert to Upper case. So you heard correct about the InverseBinding Adapter. In InverserBinding Adapter we have to create this method for one time and you can use it any number of time.
I have implemented this using BindingAdapter and InverseBinding Adapter.In one Kotlin File, Write this two functions as follows.
Function Code
#BindingAdapter(value = ["setText", "custom:AttrChanged"], requireAll = false)
fun EditText.updateText(text: String?, listener: InverseBindingListener) {
if (this.text.toString() != text) {
this.setText(text)
}
this.doOnTextChanged { _: CharSequence?, _: Int?, _: Int?, _: Int? ->
listener.onChange()
}
}
#InverseBindingAdapter(attribute = "setText", event = "custom:AttrChanged")
fun EditText.getUpdatedText(): String? {
return this.text.toString().uppercase()
}
For Upper Case I have created one uppercase variable of MutableLiveData of type String
var uppercase = MutableLiveData("")
Now in XML i have set that property as follow:
<androidx.appcompat.widget.AppCompatEditText
android:id="#+id/edit_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp"
setText="#={viewModels.uppercase}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/btn_login_data_binding" />

what is the alternative in kotlin of (auto complete when I use new in android java )

I am try to implement seekBar1.setOnSeekBarChangeListener()
In Java, I just write new keyword and auto-complete help me implementation and know which interface I have to Implement
is there any way like this in kotlin
or I have to remember all of these Interfaces
I know there is no new keyword in kotlin , but I asked about how after I write object auto complete take place
The shortcut you are looking for is Ctrl + Shift + Space
In kotlin, use "object" keyword to implement an interface.
seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
There is no key word new in kotlin, just don't use it .
You have to use object : to override anonymous inner classes
seekBar.setOnSeekBarChangeListener(object :SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
See Docs https://kotlinlang.org/docs/reference/object-declarations.html
Use object to implement an interface.
// Set a SeekBar change listener
seek_bar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
// Do something
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
// Do something
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// Do something
}
})
Kotlin doesn't contain new keyword. So yes, according to your dilemma it's pain is the neck. But it does provide you auto-complete!
All you've to do is make object of particular interface and then it generates you error about not implementing methods from that & then by using command Alt+Enter you can implement all methods from that interface.
In your case just type:
seekBar1.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {})
Which will show you compilation error at object keyword.
If your interface is having single method implementation, you can directly use Sam-constructor implementation. I.e. for click listeners in Kotlin provides you direct autocomplete from suggestions something like :
view.setOnClickListener {
//This is the same click listener we used to implement in our Java code
}
after writed your object listener, for example;
(object:ApiCallback<JSONObject>{})
and put your cursor to above object, you'll see import method after make option+enter combination
(option+enter shurtcut valid for macbook keyboard, if you use windows u have to find another solution that have show listener implementation methods.

Two-way binding Android on edit text

I want to set up the two-way binding for Edit Text. But getting an error so far.
Could not find event 'textChangeAttrChanged' on View type 'android.widget.EditText'
This is a pretty straightforward scenario but never seen a good working example.
Part of binding adapters:
#BindingAdapter("textChange")
#JvmStatic fun setText(view: EditText, value: String) {
if (view.text.toString() != value) {
view.setText(value)
}
}
#BindingAdapter("textChangeAttrChanged")
#JvmStatic fun setTextListener(view: EditText, onTextChange: ITextChange) {
val textWatcher : TextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {
onTextChange.onTextChanged(view.text.toString())
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
}
view.addTextChangedListener(textWatcher)
}
#InverseBindingAdapter(attribute = "textChange")
#JvmStatic fun getText(editText: EditText): String {
return editText.text.toString()
}
And from XML:
<EditText
android:id="#+id/et_title_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="#string/input_address"
android:inputType="textPersonName"
android:textColorHint="#color/colorGray"
textChange="#={viewModel.searchKeyword}"
textChangeAttrChanged="#{(text) -> viewModel.onSearchEntered(text)" // adding or removing this line doesn't give a thing
tools:ignore="Autofill" />
This is not the correct way to use inverse databinding for a view model.
First, EditText already supports two-way databinding via the databinding library, so you don't have to do this on your own.
Second, you only need the inverse binding adapter stuff if you want to set up a custom view for databinding. In your case, you just want an existing view that is already set up for databinding to update your view moodel.
By using the "#={viewModel.searchKeyword}" notation, you are indicating that you have a property called "searchKeyword" that has both a getter and a setter and that you want the databinding library to invoke the setter with the value from the view when it changes.
Thus, all you should need to do is implement your logic in your property setter. Something like this:
#Bindable var searchKeyord : String? = null
set(value) {
if (field != value) {
field = value
onSearchEntered(value)
notifyPropertyChanged(BR.searchKeyword)
}
}
Please review the databinding documentation for more info.
Hope that helps!

Inline onFocusChange kotlin

I'm trying to build an inline function for setOnFocusChangeListener
This is what I got so far:
inline fun EditText.onFocusChange(crossinline hasFocus: (Boolean) -> Unit) {
setOnFocusChangeListener(View.OnFocusChangeListener { view, b -> })
}
And I use it like this
freightTimeOfDay.onFocusChange { doSomething() }
Unfortunately though it gives me no errors, doSomething() is never called.
I'm looking for two things here:
1 - Get a param in there so I can pass it on to doSomething().
For example
freightTimeOfDay.onFocusChange { doSomething(hasFocus) }
2 - Make it work :p, as right now nothing is happening.
Update:
Seems like kotlin already has some type of inline for this
editText.setOnFocusChangeListener { view, b -> doSomething(b) }
However this isn't working for me either, doSomething(hasFocus: Boolean) is never called.
Thanks in advance!
Just to clarify, there isn't really a point in creating an inline method extension.
This was my initial objective but I later realized that using:
editText.setOnFocusChangeListener { view, b -> doSomething(b) }
was possible, it's inline, it's pretty and no extra work is needed
You simply forgot to call hasFocus:
setOnFocusChangeListener(View.OnFocusChangeListener { view, b -> hasFocus(b) })
/\/\/\/\/\
This is a sweet and readable syntax:
yourEditText.setOnFocusChangeListener { _, hasFocus ->
if (hasFocus)
showSomething()
else
hideSomething()
}
I know this is an old question but someone else might find it useful.
"Your_edittext_id".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) {
Your_Function()
}
})
Just paste this snippet in your oncreate function.
PS: I found this solution on this website

Categories

Resources