I'm facing an issue without being able to find an answer. I have an editText with a TextWatcher to find a list of results in a database. I display the result in a PopupMenu. It looks like this :
final List<SearchResult> searchResults = new ArrayList<>();
final PopupMenu menu = new PopupMenu(getActivity(), binding.bottomSheetWriteNews.editTextNewsSubCategory);
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
binding
.bottomSheetWriteNews
.editTextNewsSubCategory
.setText(item.getTitle());
return false;
}
});
final Realm realm = Realm.getDefaultInstance();
binding.bottomSheetWriteNews.editTextNewsSubCategory.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
searchResults.clear();
menu.getMenu().clear();
RealmResults<SubCategory> subCategoriesResult = realm.where(SubCategory.class).contains("name", s.toString(), Case.INSENSITIVE).findAll();
for(SubCategory subCategory : subCategoriesResult) {
searchResults.add(new SearchResult(subCategory.getId(), subCategory.getName(), false));
menu.getMenu().add(subCategory.getName());
}
menu.show();
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
My issue is every-time I click on the Keyboard the PopupMenu is dismiss instead of typing the character I wanted. That's annoying and unusable for users. I want the click on keyboard to not dismiss the PopupMenu. I know that in the official documentation it's written Touching outside of the popup will dismiss it, but I'm using Google Keep, and they have the same feature (typing text display a PopupMenu to filter results) without my issue.
Thanks for your help !
Instead of using popup menu you can use
spinner or (list view or recycler view )
and do notifyDataSetChanged().
So that the layout won't get piling(off and on)
Hope it will help you.
Responding to my own answer after I found an alternative solution with a coworker. There is a specific EditText named autoCompleteTextView which can take an ArrayAdapter. And it will do the search for you. Here is how I implemented it :
final Realm realm = Realm.getDefaultInstance();
RealmResults<SubCategory> subCategoriesResult = realm.where(SubCategory.class).findAll();
List<String> categoryName = new ArrayList<>();
for(SubCategory subCategory : subCategoriesResult) {
categoryName.add(subCategory.getName());
}
String[] stringArray = categoryName.toArray(new String[0]);
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
android.R.layout.simple_dropdown_item_1line, stringArray);
binding.bottomSheetWriteNews.autoCompleteTextViewNewsSubCategory.setAdapter(adapter);
And nothing more ! After typing two characters the list of result will show as a PopupMenu.
In any case, if someone has a solution to avoid dismiss after clicking on keyboard when a PopupMenu is showed, I'm interested. Thanks !
Related
I have a question:
I have a listview (from custom adapter) with a searchbar on top of it. Everything works ok, the only thing I need is when opening the activity to keep the listview hidden, or invisible, until the search has started in the searchbar (in other words, to keep the listview hidden until I start typing something in the searchbar).
You can find the code here:
How to start new intent after search-filtering listview?
Plus a suggested solution, which unfortunately did not work, you can see here:
Android search list invisible by default? Can it be done?
I am looking forward to your replies guys and I thank you in advance.
Try adding TextWatcher to your search EditText. This will detect when you type something in your search:
EditText search= (EditText) findViewById(R.id.search);
search.addTextChangedListener(filterTextWatcher);
TextWatcher method:
private TextWatcher filterTextWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
//Change the visibility here
list.setVisibility(View.VISIBLE);
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
};
I think you may be thinking about an AutoCompleteTextView? It requires that you load the list data into its adapter then set the adapter.
// Get a reference to the AutoCompleteTextView in the layout
AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.autocomplete_country);
// Get the string array
String[] countries = getResources().getStringArray(R.array.countries_array);
// Create the adapter and set it to the AutoCompleteTextView
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, countries);
textView.setAdapter(adapter);
Google's Guide: here.
I've looked up a few tutorials online but decided the following was the best approach.
My Activity only consists of a text field (editText) and a list view (roomlv)
CODE
The objects contained in the list are RoomCell objects
My Class has the following variables
public class RoomsActivity extends ActionBarActivity {
ListView listview2;
RoomCell[] roomcells = {rc1, rc2, rc3, rc4, rc5, rc6, rc7, rc8, rc9};
//where rc1, rc2, ... are predefined objects
RoomCell[] finalcells = roomcells;
RoomListAdapter rla;
My onCreate method looks like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rooms);
listview2 = (ListView) findViewById(R.id.roomlv);
listview2.setClickable(true);
listview2.setOnItemClickListener(onListClick2);
EditText filterText = (EditText) findViewById(R.id.editText);
filterText.addTextChangedListener(filterTextWatcher);
rla = new RoomListAdapter(this, finalcells);
listview2.setAdapter(rla);
}
where my TextWatcher works like this:
private TextWatcher filterTextWatcher = new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before,
int count) {
if(s.length()==0){
finalcells = roomcells;
rla.notifyDataSetChanged();
}else{
finalcells = filterList(roomcells, s);
rla.notifyDataSetChanged();
}
}
};
where the other 2 override methods are omitted for convenience here.
The filterList() method returns the filtered array (this, I believe is working fine but I will paste the code if asked for)
And finally the OnClick code is here:
private AdapterView.OnItemClickListener onListClick2 = new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
GlobVar.roomtitle = finalcells[position].name;
GlobVar.roomsize = finalcells[position].size;
Intent i = new Intent(RoomsActivity.this, TheRoomActivity.class);
startActivity(i);
}
};
where 2 global variables are assigned specific values to the clicked cells.
PROBLEM
Editing the text field makes no difference whatsoever, and clicking on a cell crashes my program?
I've looked over my code countless times and cannot locate any mistakes.
Thanks for any help in advance.
You need to call:
rla = new RoomListAdapter(RoomsActivity.this, finalcells);
listview2.setAdapter(rla);
before calling:
rla.notifyDataSetChanged();
inside your onTextChanged method as it will have new filtered objects each time you type into your EditText
I have a DialogFragment and in it's layout I have a EditText and a ListView. The Listview basically shows the list of contacts (Initially this list has 0 items). When the edittext's value is updated I populate the list with contacts that have the text typed in the EditText.
On the EditText I have used a addTextChangedListener to update the list with desired contacts as the user types in a name or email address of the contact.
The weird problem I am facing is that the list (or maybe the layout) gets updated only when I press the back button to hide the keyboard after typing. As long as the soft keyboard is showing the the list does not get updated (Except for the very first time when items are added to the empty list).
Following is some of the code for better understanding.
CustomDialogFragment.java
(in onCreateView):
// Set list adapter for contacts list
contactsList = (ListView) shareView.findViewById(R.id.contactList);
emailContactAdapter = new EmailContactAdapter(getActivity(), emailContacts, shareFragment);
contactsList.setAdapter(emailContactAdapter);
// Implement Phone-book contact share
sendToInput = (EditText) shareView.findViewById(R.id.contact_name);
sendToInput.addTextChangedListener(onContactNameSearch);
in onContactNameSearch (TextWatcher):
public TextWatcher onContactNameSearch = new TextWatcher() {
private generics commonMethods = new generics();
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
emailContacts.clear();
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
Log.d("DEBUG::REACH", "After Text Changed called");
String textValue = s.toString();
// Show or hide the share apps list based on user input
// and whether or not the list is already showing or not
if (textValue.equals("")) {
Log.d("DEBUG::REACH", "TEXT value is empty");
showAppList();
emailContacts.clear();
} else {
Log.d("DEBUG::REACH", "TEXT has value");
// Hide app list if visible
if (isAppListShowing()) hideAppList();
// Get the email contacts list based on the user query
emailContacts.addAll(commonMethods.getEmailContacts(appContext, textValue));
}
adapter.notifyDataSetChanged();
}
My assumption is that the list adapter's list is correctly updated but due to some reason the layout does not reflect the new changes until the soft keyboard is hidden.
Questions:
Has anyone faced a similar issue before (Could not find any resources while googling :/) ?
Why does this happen ?
Is there anything related to this in the official docs ?
What's the best way to resolve this ?
PS: The code in the afterTextChanged method was previously in the onTextChanged method and I was facing the same issue.
UPDATE (Added screenshots for better understanding)
The following is when the dialog fragment is shown and no text has been typed in the edittext.
Now when I type in "A" and the list populates.
I add another few letters but the list does not update. I added letters "mit" so now the query becomes "Amit" but no change in the list.
Now when I press the hardware back button on the device to hide the keyboard. The keyboard is hidden and the list is updated.
(Please do not mind the overlapping contact names and emails, still have to fix the layout :P)
UPDATE2 (Adding EmailContactAdapter code)
Following is the EmailContactAdapter class
public class EmailContactAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<EmailContact> contacts;
private ProductShareFragment fragment;
private LayoutInflater inflater;
/**
* Constructor
*/
public EmailContactAdapter(Activity activity, ArrayList<EmailContact> contacts, ProductShareFragment fragment) {
this.activity = activity;
this.contacts = contacts;
this.fragment = fragment;
}
#Override
public int getCount() {
return contacts.size();
}
#Override
public Object getItem(int position) {
return contacts.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (inflater == null) {
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
if (convertView == null) {
convertView = inflater.inflate(R.layout.email_contact_list_row, null);
}
EmailContact contact = contacts.get(position);
ImageView contactImage = (ImageView) convertView.findViewById(R.id.email_contact_image);
TextView contactName = (TextView) convertView.findViewById(R.id.email_contact_name);
TextView contactEmail = (TextView) convertView.findViewById(R.id.email_contact_email);
// contactImage.setImageBitmap(contact.getImage());
contactName.setText(contact.getName());
contactEmail.setText(contact.getEmail());
return convertView;
}
}
You are trying to change visible list with changing emailContacts, but adapter still contains old list data.
Solution: after each new text in EditText create new adapter (is a VERY bad way), or create method in EmailContactAdapter to replace items - in your case contacts field.
In the below code, you are populating the list with the result of commonMethods.getEmailContacts
// Get the email contacts list based on the user query
emailContacts.addAll(commonMethods.getEmailContacts(appContext, textValue));
Surely you first need to do emailContacts.Clear() otherwise the list is not going to change?
Try delete all emailContacts.clear();. Then add emailContacts.clear(); just before emailContacts.addAll(commonMethods.getEmailContacts(appContext, textValue));. You are appending your list for every letter your typed.
I do have a list of possibly several thousands items (just testing with shorter list with about 200 items). The information is stored in SQLite, the ContentProvider, loader and SimpleCursorAdapter is used. The list is sorted lexicographically, and the android:fastScrollEnabled is used. The list scrolls smoothly -- no problem when one knows the exact name of the item.
Occasionally, I would like to find the items that contain some substring somewhere in the middle of their name. The `... LIKE "%wanted%" is a solution for me. However, I would like to give the user an incremental filtering -- i.e. the list content be updated during typing the substring. The reasoning is that it may not be neccessary to type many characters, and one should find the item as soon as possible. The goal is not to find one or none item. The goal is to filter the list so that manual scrolling be acceptable to overview the candidate items and select one of them by touch.
I have met the SearchView widget that looks nicely at the action bar. Anyway, reading something more about it in the doc, I am not sure if it is the right tool for me. Or if the recommended implementation is the one for me. (I am an android beginner, I am even not sure if I understand it well.)
Is it possible to use the widget for incremental filtering of the list in the same activity that has the SearchView in the Action Bar? Can you point me to some code that possibly shows how to implement the wanted behaviour?
Sample code to try out :
public class AndroidListViewFilterActivity extends Activity {
ArrayAdapter<String> dataAdapter = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Generate list View from ArrayList
displayListView();
}
private void displayListView() {
//Array list of countries
List<String> countryList = new ArrayList<String>();
countryList.add("Aruba");
countryList.add("Anguilla");
countryList.add("Netherlands Antilles");
countryList.add("Antigua and Barbuda");
countryList.add("Bahamas");
countryList.add("Belize");
countryList.add("Bermuda");
countryList.add("Barbados");
countryList.add("Canada");
countryList.add("Costa Rica");
countryList.add("Cuba");
countryList.add("Cayman Islands");
countryList.add("Dominica");
countryList.add("Dominican Republic");
countryList.add("Guadeloupe");
countryList.add("Grenada");
//create an ArrayAdaptar from the String Array
dataAdapter = new ArrayAdapter<String>(this,R.layout.country_list, countryList);
ListView listView = (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
//enables filtering for the contents of the given ListView
listView.setTextFilterEnabled(true);
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
// When clicked, show a toast with the TextView text
Toast.makeText(getApplicationContext(),((TextView) view).getText(), Toast.LENGTH_SHORT).show();
}
});
EditText myFilter = (EditText) findViewById(R.id.myFilter);
myFilter.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
dataAdapter.getFilter().filter(s.toString());
}
});
}
}
I've tried to filter my ListView from my EditText box, but currently, it's not working.
I have a ListView that get data properly and they are added to my own ListView using a ArrayAdapter class and my own ArrayList class. When I for example, typing in "table" I want it to sort from the loaded titles in my ListView and than it should show me the items that are left and matching table.
My current code:
private ArrayList<Order> orders; /* ArrayList class with my own Order class to
define title, info etc. */
private OrderAdapter adapter; //Own class that extends ArrayAdapter
orders = new ArrayList<Order>();
adapter = new OrderAdapter(this, R.layout.listrow, orders); /* listrow defining a
single item in my ListView */
setListAdapter(adapter); //Set our adapter to a ListView
search.addTextChangedListener(filterTextWatcher); //search is my EditText
private TextWatcher filterTextWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
adapter.getFilter().filter(s); //Filter from my adapter
adapter.notifyDataSetChanged(); //Update my view
}
};
Okay, so how can I achieve this? When I entering some value into the EditText box everything disappear, even if there is a match.
Thanks in advance and tell me if you need more code snippets or if this question i unclear!
The built-in filter implemented by ArrayAdapter converts the contained object to string by calling toString() method. It is this string that will be used to perform the matching. If you are only trying to match one string field in your Order object, you can override the toString() method for your Order class to return that field. If you want to perform more flexible matching, such as matching multiple fields, check out this post which shows how to create a custom filter:
Custom filtering in Android using ArrayAdapter