Search in Android ListView - android

I am trying to add a search the ListView capability following this tutorial. The problem is that I am not able to show anything when I type something in the search EditText. I want to be able to display what the user is searching but that is not what's happening. What changes do I need to make to the following code so this can be achieved?
Code:
private void loadList()
{
Cursor res = tbl_business_desc.getRegisterData();
int count = res.getCount();
lvListItemsData = new android.projects.helper.mylist.ListViewItems[count];
res.moveToFirst();
for (int i = 0; i < count; i++)
{
String ControlNum = res.getString(res.getColumnIndex(tbl_business_desc.col_ControlNum));
String BizName = res.getString(res.getColumnIndex(tbl_business_desc.col_BizName));
String Owner = res.getString(res.getColumnIndex(tbl_business_desc.col_Owner));
String Add = res.getString(res.getColumnIndex(tbl_business_desc.col_Add));
String Tel = res.getString(res.getColumnIndex(tbl_business_desc.col_Tel));
String Email = res.getString(res.getColumnIndex(tbl_business_desc.col_Email));
lvListItemsData[i] = new android.projects.helper.mylist.ListViewItems(ControlNum,BizName,Owner,Add,Tel,Email);
res.moveToNext();
}
lvList = (ListView) findViewById(R.id.lvMylist);
inputSearch = (EditText) findViewById(R.id.inputSearch);
// Set the adapter to our ListView
lvListadapter = new android.projects.helper.list.ListViewItemsAdapter(this, R.layout.listview_item_row_masterlist_body, lvListItemsData);
lvList.setAdapter(lvListadapter);
/**
* Enabling Search Filter
* */
inputSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
// When user changed the Text
MyListActivity.this.lvListadapter.getFilter().filter(cs);
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
});
lvList.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
showStatus(position);
}
});
}
ListViewItemAdapter Code
public class ListViewItemsAdapter extends ArrayAdapter<ListViewItems> {
Context mContext;
int layoutResourceId;
ListViewItems data[] = null;
public ListViewItemsAdapter(Context mContext, int layoutResourceId, ListViewItems[] data) {
super(mContext, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.mContext = mContext;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItem = convertView;
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
listItem = inflater.inflate(layoutResourceId, parent, false);
// get the elements in the layout
TextView textControlNum = (TextView) listItem
.findViewById(R.id.txtControlNum);
TextView textBizName = (TextView) listItem
.findViewById(R.id.txtBizName);
TextView textOwner = (TextView) listItem
.findViewById(R.id.txtOwner);
TextView textAdd = (TextView) listItem
.findViewById(R.id.txtAdd);
TextView textTel = (TextView) listItem
.findViewById(R.id.txtTel);
TextView textEmail = (TextView) listItem
.findViewById(R.id.txtEmail);
ListViewItems listViewItems = data[position];
try {
textControlNum.setText(listViewItems.ControlNum);
textBizName.setText(listViewItems.BizName);
textOwner.setText(listViewItems.Owner);
textAdd.setText(listViewItems.Add);
textTel.setText(listViewItems.Tel);
textEmail.setText(listViewItems.Email);
}
catch (Exception e){}
if(position % 2 == 0){
listItem.setBackgroundColor(Color.rgb(243,251,254));
}else{
listItem.setBackgroundColor(Color.rgb(255,255,255));
}
return listItem;
}
}

You might need to overrride filter in your adapter class. See this SO answer. Hope that will help.

First, add a break point at line
MyListActivity.this.lvListadapter.getFilter().filter(cs);
to see whether the event has been triggered by text change.
Second, as you could see in source code of ArrayFilter, it filters the item by code
if (valueText.startsWith(prefixString)) {
newValues.add(value);
} else {
final String[] words = valueText.split(" ");
for (String word : words) {
if (word.startsWith(prefixString)) {
newValues.add(value);
break;
}
}
}
Therefore, if there is nothing left, it might be that, it should be nothing left.

Related

RecyclerView shows previous values entered in an EditText in new rows

I'm creating an android app, in which I'm using recyclerView and the row of recyclerView is having editText.
This is my ReadingAdapter class
public class ReadingAdapter extends RecyclerView.Adapter<ReadingAdapter.ViewHolder> implements AdapterView.OnItemSelectedListener {
Context context;
String valOpenReading, valClosReading, valConsumption;
private List<ReadingData> readingList;
static String[] arrValOpenRead, arrValClosRead, arrValConsumption;
public ReadingAdapter(Context context, List<ReadingData> readingList) {
this.context = context;
this.readingList = readingList;
arrValOpenRead = new String[readingList.size()];
arrValClosRead = new String[readingList.size()];
arrValConsumption = new String[readingList.size()];
}
#Override
public ReadingAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.reading_sheet_layout, parent, false);
return new ReadingAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(final ReadingAdapter.ViewHolder holder, final int position) {
ReadingData tempData = readingList.get(position);
holder.pdtName.setText(tempData.pdtName);
holder.keyId.setText("Key "+tempData.keyId);
holder.etClosRead.addTextChangedListener(new TextWatcher() {
boolean ignore = false;
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if (ignore)
return;
ignore = true;
valOpenReading = holder.etOpenRead.getText().toString();
arrValOpenRead[position] = valOpenReading;
valClosReading = s.toString().equals("") ? "0": s.toString();
arrValClosRead[position] = valClosReading;
if (!valOpenReading.equals("")) {
if (Integer.parseInt(valClosReading) < Integer.parseInt(valOpenReading)) {
Toast.makeText(context, "Check once! closing reading should be more than opening reading!", Toast.LENGTH_LONG).show();
valConsumption = "0";
holder.consumption.setText("");
} else {
valConsumption = (Integer.parseInt(valClosReading) - Integer.parseInt(valOpenReading))+"";
arrValConsumption[position] = valConsumption;
holder.consumption.setText(valConsumption);
}
} else
Toast.makeText(context, "Please fill the opening reading!", Toast.LENGTH_SHORT).show();
ignore = false;
}
});
}
#Override
public int getItemCount() {
return readingList.size();
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView pdtName, keyId, consumption;
EditText etOpenRead, etClosRead;
public ViewHolder(View view) {
super(view);
pdtName = (TextView)view.findViewById(R.id.txt_list_pdt_supp);
keyId = (TextView)view.findViewById(R.id.key_set);
etOpenRead = (EditText)view.findViewById(R.id.open_val_set);
etClosRead = (EditText)view.findViewById(R.id.clos_val_set);
consumption = (TextView)view.findViewById(R.id.consumption_val);
}
}
}
This is my ReadingData.java
public class ReadingData {
String pdtName, keyId, openReading, closReading, consumption;
public ReadingData(String pdtName, String keyId) {
this.pdtName = pdtName;
this.keyId = keyId;
}
}
Here, if I enter value in the starting items of the recyclerView then as I scroll up the items to the bottom of the list, the last item will have that value.
Please ignore the quality of image as we can't upload above of 2MiB of snap.
Here the views are recycled as the list is scrolled. How to prevent the copying values to the other item in the list.
And that Toast is also repeated several times. How to stop this.
update:
By the suggetion of LQ Gioan through the SO question How ListView's recycling mechanism works , I got the logic how ListView actually works with recycling of views.
But I'm not sure whether the recyclerView also works same.
But here in my case, how can I implement this process. pls someone help me here.
RecyclerView reuse views, in fact it only generate the as many as views that is visible on the screen. so it's expected if you can see a value you set for other rows
The solution would be set all attributes of the view that you are changing to default or whatever the row should present from your data set
So put addTextChangedListener insode ViewHolder constructor(you can get position by calling getAdapterPosition()) for better performance and set the editText value inside onBindViewHolder method from your data set
Your Activity Code:
ListView listview = (ListView) findViewById(R.id.list_view);
listview.setItemsCanFocus(true);
Adapter adapter = new Adapter (YourActivity.this, YourArrayList);
listview .setAdapter(adapter);
Adapter class
public class Adapter extends BaseAdapter {
// Declare Variables \\
Context mContext;
LayoutInflater inflater;
Activity act;
String[] temp;
public Adapter(Context context, ArrayList<String> list) {
mContext = context;
inflater = LayoutInflater.from(mContext);
act = (Activity) context;
//-------Temp String Array-------\\
temp = new String[this.count];
for (int i = 0; i < this.count; i++) {
temp[i] = list.get(i);
}
//---------------------------\\
}
public class ViewHolder {
TextView optionTitle;
EditText optionText;
int ref;
}
#Override
public int getCount() {
return list.size;
}
#Override
public Object getItem(int position) {
return temp[position];
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(final int position, View view, ViewGroup parent) {
final ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = inflater.inflate(R.layout.lv_items_add_ques_options_mcq, null);
holder.optionTitle = (TextView) view.findViewById(R.id.add_ques_opts_count_mcq_tv);
holder.optionText = (EditText) view.findViewById(R.id.add_ques_opts_title_mcq_et);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.ref = position;
holder.optionTitle.setText(getCharForNumber(position) + ":");
holder.optionText.setText(temp[position]);
holder.optionText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}
#Override
public void afterTextChanged(Editable arg0) {
temp[holder.ref] = arg0.toString().trim();
}
});
return view;
}
public void getList() {
StaticValues.arrayListOptions = new ArrayList<String>(Arrays.asList(temp));
StaticValues.arrayListOptionsCount = new ArrayList<String>();
for (int i = 0; i < count; i++) {
StaticValues.arrayListOptionsCount.add(String.valueOf(i+1));
Log.e("err_al", StaticValues.arrayListOptions.get(i));
Log.e("err_al", StaticValues.arrayListOptionsCount.get(i));
}
}
private String getCharForNumber(int i) {
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
if (i > 25) {
return null;
}
return Character.toString(alphabet[i]);
}}

add all edittexts data of listview in arraylist

I have a list view containing textview and edit texts and i have to add these values in array list.As i am trying it not all values are added to Arraylist,only values of that particular visible view gets added.How should I modify my code so that all the data gets added to arraylist.
list = (ListView) findViewById(R.id.list);
personList = new ArrayList<HashMap<String,String>>();
flags=0;
getData();
placeord=(Button)findViewById(R.id.placeorder);
placeord.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(isNetworkConnected()) {
ArrayList<String> m = new ArrayList<String>();
ArrayList<String> si = new ArrayList<String>();
EditText q;
TextView sizes;
for (int i =0; i<= list.getLastVisiblePosition() - list.getFirstVisiblePosition(); i++) {
View v = list.getChildAt(i);
q = (EditText) v.findViewById(R.id.numberofitems);
sizes = (TextView) v.findViewById(R.id.size);
if(q.getText().toString().length()>0) {
si.add(sizes.getText().toString());
flags=1;
}
m.add(q.getText().toString());
}
if (flags == 0) {
Toast.makeText(getApplicationContext(), "please add some quantity", Toast.LENGTH_SHORT).show();
} else {
//Toast.makeText(getApplicationContext(),val,Toast.LENGTH_SHORT).show();
Intent intent = new Intent(placecolor.this, placeorder2.class);
Bundle extras1 = new Bundle();
extras1.putStringArrayList("numberofitems", m);
extras1.putStringArrayList("sizes", si);
intent.putExtras(extras1);
startActivity(intent);
}
}
}
}
It happens because android recycle the view of ListView and Recyclerview. You need to add(save) data of EditText by implementing OnTextChangeListener. By implementing it you can get the entered text and assign it to particular position in List<>.
Example :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.listview_list, null);
holder.textView = (TextView) convertView.findViewById(R.id.textView);
holder.editText = (EditText) convertView.findViewById(R.id.editText);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.ref = position;
holder.textView.setText(arr[position].name);
holder.editText.setText(arr[position].nameValue);
holder.editText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
arr[holder.ref].nameValue = arg0.toString(); // Set value in list
}
});
return convertView;
}

How to get text from EditText within ListView with multiple Views?

I have a ListView that contains two TextViews and one EditText in each row. I have searched and searched and cannot figure out how to get the text that the user enters into the EditText. My most recent attempt implements a TextWatcher.
public void addIngredientToMeal(String ingredientName) {
ingredient_list = (ListView) findViewById(R.id.ingredients_in_meal_listView);
int numberOfIngredients = ingredient_list.getChildCount();
ListAdapter adapter = new ListAdapter();
adapter.name_array = new String[numberOfIngredients+1];
for (int i = 0; i < numberOfIngredients; i++)
adapter.name_array[i] = (String) ingredient_list.getItemAtPosition(i);
adapter.name_array[numberOfIngredients] = ingredientName;
ingredient_list.setItemsCanFocus(true);
ingredient_list.setAdapter(adapter);
}
private class ListAdapter extends BaseAdapter{
public String[] name_array, qty_array;
#Override
public int getCount() {
// TODO Auto-generated method stub
if(name_array != null && name_array.length != 0){
return name_array.length;
}
return 0;
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return name_array[position];
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//ViewHolder holder = null;
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
LayoutInflater inflater = NewMeal.this.getLayoutInflater();
convertView = inflater.inflate(R.layout.ingredients_in_meal_layout, null);
holder.textView1 = (TextView) convertView.findViewById(R.id.ingredient_name_in_new_meal_textView);
holder.editText1 = (EditText) convertView.findViewById(R.id.ingredient_qty_in_new_meal_editText);
holder.textView2 = (TextView) convertView.findViewById(R.id.ingredient_unit_in_new_meal_textView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.ref = position;
holder.textView1.setText(name_array[position]);
holder.textView2.setText(databaseAdapter.dbQuery(name_array[position]));
holder.editText1.setText(qty_array[position]);
holder.editText1.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable arg0) {
qty_array[holder.ref] = arg0.toString();
}
});
return convertView;
}
private class ViewHolder {
TextView textView1, textView2;
EditText editText1;
int ref;
}
}
}
For those who may have a similar issue, I solved the problem I was having.
The problem:
Need to get values entered in multiple editTexts that are contained within a listView. Using listviewname.getItemAtPosition(integer) only gets the value of the first editText. Moreover, I had multiple views contained in each row of the listview, so getItemAtPosition only returned the value of the first view in the first row of the listView.
The solution:
Define a listView object that identifies the listview that we care
about
Define a View object that can get the listview
Define whatever field(s) you are trying to get from the listview (EditTexts, TextViews Etc.)
Get the number of rows that the listview currently contains
Set the view object using listviewname.getChildAt(position)
Assign the field (say, an editText) using something like (EditText) viewObject.findViewById(R.id.edittextid)
Get the value from the field using editTextObject.getText().toString()
Here's some sample code that could be implemented on a button press:
ListView lvName = (ListView) findViewById(R.id.listview1);
View v;
EditText et;
int listLength = lv.getChildCount();
String[] valueOfEditText = new String(listLength);
for (int i = 0; i < listLength; i++)
{
v = lvName.getChildAt(i);
et = (EditText) v.findViewById(R.id.edittext1);
valueOfEditText[i] = et.getText().toString();
}
getFocusedChild(position) it will return a View, or findFocus()
View row = ingredient_list.getFocusedChild();
EditText et = (EditText)row.findViewById(R.id.ingredient_qty_in_new_meal_editText);
Edit
Sorry i misunderstood create a gist will toast with the input
https://gist.github.com/imjarp/9313c687ccbe339d052f

Filter listview, i can't understand filter rule

i need apply a filter for a ListView. I read a lot of documentation but i can't understand the rule of the filter. The filter works but i don't know what are it doing.
I use this class:
public class ArtistasActivity extends Activity {
private EditText filterText = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View title = getWindow().findViewById(android.R.id.title);
View titleBar = (View) title.getParent();
titleBar.setBackgroundColor(Color.rgb(181, 9, 97));
setContentView(R.layout.artistas_l);
final ListView m_listview = (ListView) findViewById(R.id.listView1);
ListAdaptor adaptor = new ListAdaptor(this, R.layout.artistas_l, loadArtistas());
m_listview.setFastScrollEnabled(true);
m_listview.setScrollingCacheEnabled(true);
m_listview.setAdapter(adaptor);
m_listview.setTextFilterEnabled(true);
// Search
filterText = (EditText) findViewById(R.id.search_box);
filterText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
}
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}
public void afterTextChanged(Editable text) {
Log.d("search", ""+text);
ListAdaptor adaptor = (ListAdaptor) m_listview.getAdapter();
adaptor.getFilter().filter(text);
adaptor.notifyDataSetChanged();
}
});
And ListAdaptor is typical:
private class ListAdaptor extends ArrayAdapter<Artista> {
private ArrayList<Artista> artistas;
public ListAdaptor(Context context, int textViewResourceId, ArrayList<Artista> items) {
super(context, textViewResourceId, items);
this.artistas = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.artistas_list, null);
}
Object content = null;
Artista o = artistas.get(position);
TextView tt = (TextView) v.findViewById(R.id.ArtistTopText);
tt.setText(o.getNombre());
v.setClickable(true);
v.setFocusable(true);
v.setOnClickListener(myClickListener);
return v;
}
}
The aplications works, and when write in the texteditor the list is filtered but when i put a R, appear names with Dani or Diego...
I override the toString method for only return de name.
#Override
public String toString() {
return this.nombre;
}
Thx for help !! Rgds
There is no need to maintain the aristas array member, as you are already passing it to the super. In the getView method, get the item by calling getItem(position).. This correction will fix the problem..

Filtering using TextWatcher on a ListView backed by a String ArrayAdapter returns empty results

The following code returns 0 views in listview on entering any character in search EditText.
Following method is from activty class
private void setupList() {
final ListView lv = (ListView) findViewById(R.id.contactList);
ArrayAdapter<Info> la = new MyListAdapter(this, mInfoList);
lv.setAdapter(la);
lv.setTextFilterEnabled(true);
EditText edit = (EditText) findViewById(R.id.searchbar);
edit.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}
#Override
public void afterTextChanged(Editable text) {
Log.d("search", ""+text);
ArrayAdapter<Info> la = (ArrayAdapter<Info>) lv.getAdapter();
la.getFilter().filter(text);
la.notifyDataSetChanged();
}
});
}
This is my adapter class
public class MyListAdapter extends ArrayAdapter<Info> {
private Bitmap mDefaultProfilePic = null;
Context mContext = null;
public MyListAdapter(Context ctxt, ArrayList<Info> mFriendsAccounts) {
super(ctxt, R.id.name, mFriendsAccounts);
mContext = ctxt;
mDefaultProfilePic = BitmapFactory.decodeResource(ctxt.getResources(), R.drawable.face);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inf = (LayoutInflater) mContext.getSystemService(Service.LAYOUT_INFLATER_SERVICE);
convertView = inf.inflate(R.layout.layout_list_view, null);
}
Info usr = getItem(position);
((TextView)convertView.findViewById(R.id.name)).setText(usr.Name);
((ImageView)convertView.findViewById(R.id.invite)).setTag(position);
if (mImageBitmaps.get(position) != null) {
((ImageView)convertView.findViewById(R.id.profilePic)).setImageBitmap(mImageBitmaps.get(position));
} else {
((ImageView)convertView.findViewById(R.id.profilePic)).setImageBitmap(mDefaultProfilePic);
}
return convertView;
}
}
Finally fixed the problem. I had to override the toString() method in Info object. In my case filtering is based on name field so returned it through toString().
The filtering process calls the toString() on each object in the adapter.
Here it says:
The returned adapter might not be the same adapter passed to
setAdapter(ListAdapter) but might be a WrapperListAdapter
Could this have anything to do with your issue?

Categories

Resources