Combine both on text change and debounce in rxjava for edittext - android

I've been using rxjava2 for a while but mostly kind of a boilerplate, I didn't clearly know its features.
I supposed to create a search Edittext which call method after sometime. I got it working by the following code:
RxTextView.textChanges(edittextSearch)
.filter(charSequence -> charSequence.length() > 3)
.debounce(800, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(string -> {
search(string.toString());
}, error -> {
Log.e("ERROR","ERROR LISTENING: " + error.getMessage());
});
However, I need one more feature for this EditText, which is as soon as I type, even with just one character, I would display an "X" icon to clear the input, or hide it if user manually delete all text.
I don't know if the textChanges method above could do that or I have to add another text watcher for the edittextSearch
Thank you for your time.

You can achieve what you want by using a TextInputLayout and adding app:endIconMode="clear_text". It's part of the material design library, there are plenty of guides on how to use them.
This will automatically add a clear icon when the user begins typing, clicking the icon will clear the text and update your textChanges observable.

Related

Preventing double clicking in components throughout entire app

I know how to prevent double-clicking on a component. What I want to know if there is some way to avoid this behaviour "by default" when adding a component. Do I have to go every single item that can be clicked in an app and write the same code for every single component?
I know I could subclass, say, Button class, write the code for preventing double-clicking there, and only use my Button class in the app. What is the point of it? Why isn't something like that in the default Android Button class? I haven't seen any intended double-clicking behaviour in ANY app. Do I have to write a subclass of every single View that is susceptible of being clicked in order to prevent this? is there something I am missing?
Just to clarify, my question is about something like disableDoubleClick() method or something like that. I already said I know how to prevent this, but is a bit of a hassle to do it for every single clickable item in an app.
You can use Kotlin with its extensions in conjunction with reactive bindings of RxJava.
for the general view it will look something like:
fun View.clickWithDebounce(debounceTime: Long = 600L, action: () -> Unit): Disposable =
RxView.clicks(this)
.debounce(debounceTime, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { action() }
Use it like this:
button.clickWithDebounce{
//do stuff
}
textView.clickWithDebounce{
//do other stuff
}
imageView.clickWithDebounce{
//do some completely unrelated with the previous two stuff
}
floatingButton.clickWithDebounce(100000000){
//do some stuff and wait 100000 seconds before the next click
}
For more info: Kotlin Extensions, RxJava RxBinding
Hope it helps.

Android Studio autocomplete wrap object in another object

So is my existing code:
fun getAllPeople(): List<People> {
return peopleDao.getAll()
...
}
and I want to wrap the List<People> in a LiveData object.
When I start typing in the front, autocomplete gives me the suggestion for LiveData here,
but then when I hit enter it completes to this.
I know I can then type < and move to the end and type >.
But isn't there an easy way to wrap something with another object correctly?
You can do this for your current selection with a custom live template:
Go to Settings -> Editor -> Live Templates
Under Android, add a new template (Alt+Insert or the green 'plus' button on the right)
Give an abbreviation and a description to your template
Set the template text to LiveData<$SELECTION$>
Set the applicable contexts to Java and Kotlin
Click Apply
Now when you select your List<People> and use "Surround with Live Template" (Ctrl+Alt+J on Windows/Linux, Cmd+Alt+J on Mac by default), you can choose your custom template from the list and watch as the selected declaration becomes LiveData<List<People>>.
Tip: You can also use the "Extend Selection" shortcut to more easily select the declaration (Ctrl+W on Win/Linux, Alt+Up on Mac by default).

AutoCompleteTextView item selection programmatically

I have an AutoCompleteTextView that is filled with cities from an sqlite database that calls an AsyncTask on item click, recently I added an option to detect my location using the gps, so the problem is I can detect the city (i.e Beirut) and set the text for the AutoCompleteTextView but the thing is that the dropdown filter opens showing Beirut (which is correct) but I still need to click on the list item to invoke the listener, how to do so programmatically
How to:
Enter the Activity (DONE)
Detect location (DONE)
set text of text view (DONE)
show textview dropdown list(DONE)
choose the item that will be returned, since it will only return one city (NOT DONE)
To be clear, Tano's solution is sufficient to answer this question. But, in case others run into the same use case I did, here's some more background that may potentially help you...
I had been running into this issue specifically while trying to make a non-editable Material Exposed Dropdown Menu and set it's initial value programmatically. The documentation to create this type of "dropdown" can be found in the Exposed Dropdown Menus section here, which suggests a mechanism using TextInputLayout and AutocompleteTextView (even if you don't want autocomplete functionality).
Failed Solution 1:
At first glance setListSelection() and getListSelection() seemed like they might do the trick. But after many trials, I learned that they may not be sufficient because they only work when the list popup isShowing(). So for example, if you simply want to set the initial selection without having to show the list popup first, this will not work.
Failed Solution 2:
Then I tried setText() which showed the proper text in my textbox. Yay! But wait! When I clicked on the text view, only a subset of options in the list popup were shown for some reason. Why was that? The key thing to keep in mind here is that since this is an autocomplete textview, it by default filters out options based off of the text in the textview. This might not be apparent, especially if you're solely using this control for the sake of making a simple non-editable dropdown selector.
Solution:
This brings us to our actual solution (suggested by Tano)... setText() with filter as false will turn off the filtering capabilities AND it will not change the contents of your list popup.
autoCompleteTextView.setText(myText, false);
I was facing a similar problem and this solved my issue. Important is to call setText(<text>, <filter boolean>) in order not to filter with the given text set the second parameter with false. The text will be got from the dropdown adapter.
Solution snippet:
automCompleteTextView.setText(automCompleteTextView.getAdapter().getItem(position).toString(), false);
A solution were you don't need to change your API level.
automCompleteTextView.setAdapter(adapter);
// set default selection, filtering is active so all items is not visible in drop-down menu
automCompleteTextView.setText(automCompleteTextView.getAdapter().getItem(0).toString());
// change filtering for the adapter so all items can be visible in drop-down menu
adapter.getFilter().filter(null);
one-liner for the same job but requires higher API level
automCompleteTextView.setText(automCompleteTextView.getAdapter().getItem(0).toString(), false);
I figure out after dig into the AutoCompleteTextView code on android source code:
fun AutoCompleteTextView.selectItem(text: String, position: Int = 0) {
this.setText(text)
this.showDropDown()
this.setSelection(position)
this.listSelection = position
this.performCompletion()
}
autoComplete.setListSelection(position);
I have used autoCompleteTextView.setText(myText, false); solution as well, however it sometimes failed. I mean it was actively filtering results so, when user clicks there was only 1 item at dropdown.
In addition I also needed this to work on custom objects as well, and this is my my solution:
binding.hourEditText.configureDropDownMenu(viewModel.hours) { it.hourString() }
.subscribe {
// Do whatever you need when on click.
}
.addTo(disposables)
fun <T> AutoCompleteTextView.configureDropDownMenu(list: List<T>, toString: ((T) -> String)? = null): Observable<T> {
keyListener = null
val textItems = toString?.let(list::map) ?: list.map { it.toString() }
setAdapter(NonFilterArrayAdapter(context!!, android.R.layout.simple_spinner_dropdown_item, textItems))
return itemClickEvents().map {
list[it.position]
}
}
private class NonFilterArrayAdapter<T>(context: Context, #LayoutRes resource: Int, objects: List<T>) : ArrayAdapter<T>(context, resource, objects) {
override fun getFilter() = NonFilter()
private class NonFilter : Filter() {
override fun performFiltering(constraint: CharSequence?) = FilterResults()
override fun publishResults(constraint: CharSequence?, results: FilterResults?) = Unit
}
}
Note: This also contains a bit of Rx, but it can be removed easily.
Try with adding below after setText() in AutoCompleteTextview:-
autoCompleteTV.setSelection(position);
Updated:
This will work in Spinner and AutoCompleteTextView which has dropdown feature, but it will not work with EditText.
Here you can check docs for AbsSpinner in this link:
https://developer.android.com/reference/android/widget/AbsSpinner.html#setSelection(int)
The problem is that you are setting a text and the AutoCompleteTextView is only showing words that match with that text. A non elegant way of solving this is to set an high threshold (at least the max length of the names of the cities) to force Android to show you all the values of your list (this threshold is the number of characters that the field must have to search similarities).
Using the Nilton Vasques solution it can be so:
with(autoComplete) {
setAdapter(this#YourFragment.adapter)
setText(itemText)
showDropDown()
listSelection = if (itemIndex > 0) itemIndex - 1 else 0 // Because AutoCompleteTextView shows the next row.
performCompletion()
}
Notice, that it will show a drop-down list, otherwise listSelection won't work. If you call dismissDropDown(), the item won't be selected. If you don't want to show the drop-down list, you can use setOnTouchListener to capture opening the list, but it hardly will help (you should resolve a filtering problem).
setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
showDropDown()
listSelection = if (itemIndex > 0) itemIndex - 1 else 0
performCompletion()
requestFocus()
}
false
}

setBackgroundColor method, android

Right now I'm building a simple form and I'm designing it so that if the user hasn't entered the necessary info before clicking the submit button the background turns red. And after if they have entered the correct info the form goes back to the way it was before.
// "if empty then set fields to red" checks
if (firstLastName.getText().toString().equals("")) {
firstLastName.setBackgroundColor(Color.RED);
}
else
firstLastName.setBackgroundColor(Color.WHITE);
}
The problem is that white apparently isn't what it was before, because it looks different. Is there a way to reset the form without deleting the info entered by the user?
If I'm not being clear please let me know and Ill try to elaborate.
How about setting and removing a color filter instead of changing the background color:
if (firstLastName.getText().toString().equals("")) {
// 0xFFFF0000 is red
firstLastName.getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.DARKEN);}
else {
//Setting to null removes filter
firstLastName.getBackground().setColorFilter(null);
}

Text selection listener in Android(API level 7)

I need a listener which is called every time the selection in an EditText changes.
I googled around but I couldn't find anything useful for API level 7.
I'm writing a Text Editor and I want the bold/italic/underlined button appear selected every time the user selects bold/italic/underlined text.
Pretty old question, but someone might still need this, so here's my solution : since the text selection accomplished with long press on the text, I simply used the following :
editText.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
// do whatever you need to do on text selection
}
});
This allows for custom behavior on text selection and doesn't prevent the user from copying/pasting.
The better way to do it would be to extend the EditText and then based upon how you would want to manage the changing text, you could override one of the 2 methods to work out your customized behavior.
If you want the selection changed then you could use the onSelectionChanged() method and implement your code there.
In case you want to implement something when the text changes in your editor then you could use, onTextChanged().

Categories

Resources