Android: Prevent text field pop-up when entering text in a SearchView - android

Hello Android developers,
I've got a problem with the Android SearchView widget. What I'm trying to do is to attach a "live" text filter to my ListView (text input automatically refreshes filter results). It works actually fine and it was no huge effort to get it working on my ListActivity with these lines:
private SearchView listFilter;
this.listFilter = (SearchView) findViewById(R.id.listFilter);
this.listFilter.setOnQueryTextListener(this);
this.listFilter.setSubmitButtonEnabled(false);
this.getListView().setOnItemClickListener(this);
this.getListView().setTextFilterEnabled(true);
// from OnQueryTextListener
public boolean onQueryTextChange(String newText) {
if (newText.isEmpty()) {
this.getListView().clearTextFilter();
} else {
this.getListView().setFilterText(newText);
}
return true;
}
And here the xml widget declaration
<SearchView
android:id="#+id/listFilter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:iconifiedByDefault="false"
android:queryHint="enter text to filter" />
Now what my problem is that every time I enter text into the SearchView, a strange text field pops up instantly showing the same text as I just entered which is kind of useless since I can see my input in the SearchView itself and it partly blocks the sight on my list entries, which is just annoying.
Is there any way to prevent that text field from popping up on typing into the SearchView? I couldn't find any property neither on the xml defined widget options nor on the java class reference.
I know there is another way to provide the filter functionality by using EditText and TextWatcher, but then I have to handle the filtering all by myself and couldn't profit from the SearchView handling it for me.
Any suggestions are appreciated.
Best regards
Felix

i found out how to get rid of that ugly popup window. The trick is to work with filter directly.The code below assumes you have implemented filterable in your customAdapter.
public boolean onQueryTextChange(String newText) {
if (TextUtils.isEmpty(newText)) {
m_listView.clearTextFilter();
} else {
ContactsAdapter ca = (ContactsAdapter)lv.getAdapter();
ca.getFilter().filter(newText);
//following line was causing the ugly popup window.
//m_listView.setFilterText(newText);
}
return true;
}

Related

Making a calculator app w/ buttons and TextView with blinking cursor and NO keyboard focusability. Is it possible without using Canvas to draw cursor?

There is the proper method which is to draw the line myself via canvas. I want to avoid the complexity and I am asking here to double check if there is a simpler method I can use.
I am currently using a temporary method, which is to use SpannableString to highlight the nearest text 'character' that the cursor is on. But as you know, this "selects" the current character. I prefer the cursor to be between two characters instead of on top of one character.
I also don't want keyboard focus because I already laid out some nice buttons for the user to interact with. I don't want the app to use the Android keyboard and input methods. Only my buttons should be enough.
I tried accessing TextView methods:
Remove keyboard focus and input via the manifest
setFocusable(false)
setFocusableInTouchMode(false)
setCursorVisible(true) or cursorVisible="true"
This didn't work for me. I know that if I make the TextView focusable, then the cursor will be visible. But if it's not focusable, then the cursor does not show, even if it it is: cursorVisible="true".
What should I do?
Solution:
Disable input method of EditText but keep cursor blinking
Maybe try leaving out the xml attribute android:editable entirely
and then try the following in combination to
keep the cursor blinking and prevent touch events from popping up
a native IME(keyboard)..
/*customized edittext class
* for being typed in by private-to-your-app custom keyboard.
* borrowed from poster at http://stackoverflow.com/questions/4131448/android-how-to-turn-off-ime-for-an-edittext
*/
public class EditTextEx extends EditText {
public EditTextEx(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onCheckIsTextEditor() {
return false; //for some reason False leads to cursor never blinking or being visible even if setCursorVisible(true) was
called in code.
}
}
Step 2 change the above method to say return true;
Step 3 Add another method to above class.
#Override public boolean isTextSelectable(){ return true; }
Step 4 In the other location where the instance of this class has been
instantiated and called viewB I added a new touch event handler
viewB.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
viewB.setCursorVisible(true);
return false;
} });
Step 5 Check to make sure XML and or EditText instantiation code
declares IME/keyboard type to be 'none'. I didnt confirm relevance,
but Im also using the focusable attributes below.
<questionably.maybe.too.longofa.packagename.EditTextEx
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:focusable="true"
android:focusableInTouchMode="true"
android:inputType="none">
Sorry for so many xml attributes. My code uses them all, testing in
4.2.1, and has results. Hope this helps.

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
}

Android Acccessibility: How do I change the text read out loud for an EditText View

By default, the Accessibility Services will read out the following for an EditText view
If the EditText has a value entered = it will read out that value
If there is not value entered = it will read out the "hint"
I want it to read out something completely different in both cases.
My xml snippet is
<EditText
android:id="#+id/my_edit_text"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:editable="false"
android:focusable="true"
android:hint="my hint text"/>
I have to support API 14 and onwards.
I do not want to go to the trouble of extending EditText for this one single case, therefore I am using am AccessibilityDelegate.
mEditTextView.setAccessibilityDelegate(accessibilityDelegate);
From the documentation I understand that in my delegate I only have to overwrite those methods in the delegate for which I would like to change the behaviour. All other methods will default to the View's implementation.
http://developer.android.com/reference/android/view/View.AccessibilityDelegate.html
http://developer.android.com/reference/android/view/View.html
The doc for "onPopulateAccessibilityEvent" says : "Gives a chance to the host View to populate the accessibility event with its text content."
The doc for "dispatchPopulateAccessibilityEvent" says : "Dispatches an AccessibilityEvent to the host View first and then to its children for adding their text content to the event." and that the default behaviour is to call "onPopulateAccessibilityEvent" for the view itself and then "dispatchPopulateAccessibilityEvent" on all its children
http://developer.android.com/guide/topics/ui/accessibility/apps.html
This doc says under "onPopulateAccessibilityEvent" "*If your implementation of this event completely overrides the output text without allowing other parts of your layout to modify its content, then do not call the super implementation of this method in your code."
Therefore my delegate is the following
View.AccessibilityDelegate accessibilityDelegate = new View.AccessibilityDelegate() {
#Override
public void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
event.getText().add("Apples");
}
};
Why when I use the keyboard to navigate to or use the screen to tap on the EditText view it is still reading "my hint text" and not "Apples"?
If I use a debugger, I see that before I set the event text, the text is empty and after I set it, it is "Apples" yet the TalkBack still reads out the hint.
Weirdly if I overwrite "onInitializeAccessibilityNodeInfo" and send an event with my desired text, then this desired text gets read out (see code snippet below). But this seems wrong to me as the "onInitializeAccessibilityNodeInfo" is reacting to the EditText's event but then just raising a new one.
#Override
public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info){
super.onInitializeAccessibilityNodeInfo(v, info);
...
final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
event.getText().add("Pears");
event.setClassName(className);
event.setPackageName(packageName);
...
v.getParent().requestSendAccessibilityEvent(v, event);
}
We can change the text read out loud of EditText view by doing the following:
View.AccessibilityDelegate accessibilityDelegate = new View.AccessibilityDelegate() {
#Override
public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(v, info);
info.setText("some customized text")
}
};
and then set this delegate to the EditText View.
This sounds very similar to a problem I previously encountered: Android: How to eliminate spoken text from AccessibilityEvents when extending SeekBar?
Have you tried (as a test) clearing the hint text in onPopulateAccessibilityEvent, rather than just adding the 'Apples' text? I seem to remember that my empirical results did not match the Android documentation, particularly for Android OS prior to API 14.

API demo : what's this box called?

What is that little box at the bottom showing "d" called? How do I enable it in my filtered SearchView? Where else can it be used?
Could it be some kind of a Toast? I looked and looked in API sources and couldn't find how to define it.
It's a PopupWindow http://developer.android.com/reference/android/widget/PopupWindow.html. You do not need to enable it. Its used by default when you set your ListView to
listView.setTextFilterEnabled(true);
and the PopupWindow shows up when you set or clear the filter text
listView.setFilterText("d");
i found out how to get rid of that ugly popup window. The trick is to work with filter directly.The code below assumes you have implemented filterable in your customAdapter.
public boolean onQueryTextChange(String newText) {
if (TextUtils.isEmpty(newText)) {
m_listView.clearTextFilter();
} else {
ContactsAdapter ca = (ContactsAdapter)lv.getAdapter();
ca.getFilter().filter(newText);
//following line was causing the ugly popup window.
//m_listView.setFilterText(newText);
}
return true;
}
As far as I know it just repeats what you have typed in as a search key. If you have a list without a text box to type your search key, its quite handy to know what you have typed.
Cliff

How can the on-screen text selection widget be changed?

I noticed that different Android applications have different methods of selecting text. If you click-hold in Browser, there is a close up of the text plus the left and right edges can be dragged to modify the selection. In the Gmail app, a large blue circle appears below the cursor which makes it easy to move around.
The default text selection widget in an EditText box is very primitive by comparison. How can it be changed?
Update: I forgot to mention that editable is false. When editable is true the text selector is fine.
p.s. What its the proper name for the on-screen text selector?
As of Android 3.0 (API level 11), you can set the android:textIsSelectable attribute on any TextView to make its text selectable. The default UI as of this writing is similar to the behavior you referenced for the browser.
EDIT: Also, the default Android browser uses its own system-independent text selection mechanism that resembles the default text selection handles in Gingerbread. The "blue circle" sounds like a customized interface that a handset manufacturer added.
I would implement this as a custom class that extends EditText and implements LongClickListener and ClickListener. Then you can take complete control.
This is all just pseudo-code, and to point you in the right direction:
public class PrettySelectionEditText extends EditText implements OnLongClickListener, OnClickListener
{
private boolean isSelecting = false;
public PrettySelectionEditText(Context context)
{
super(context);
}
#Override
public boolean onLongClick(View v)
{
if (clickIsOnText)
{
isSelecting = true;
//Highlight word and pretty controls
}
//Select here based on the text they've clicked on?
//Return true if you want to consume the longClick
return true;
}
#Override
public void onClick(View v)
{
//If in selection mode
if (isSelecting)
{
//check where they've clicked
if (clickIsInSelect)
{
updateSelection(click);
}
else
{
isSelecting = false;
}
}
}
}
You could use a WebView instead and enable text selection.
If this is merely a problem of being unable to highlight uneditable text, you can use the XML attribute
android:textIsSelectable="true"
for that EditText box.
From the Android website:
android:textIsSelectable="true" indicates that the content of a non-editable text can be selected.
As for your question regarding terminology, I would call this the cursor.

Categories

Resources