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
Related
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)
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" />
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 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.
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