I want to make a listview item selected and the text "select" to be made to "selected", but when i click an item mutiple items get selected if I select an item at position 0 , items get selected at at a pattern, that is 0,7,14,21 and if i change the view to landscape: it will be 0 ,5,10,15, etc.
my main activity is:
public class two extends Activity implements OnQueryTextListener,OnItemClickListener {
GroupAdapter grpAdapter;
public static ArrayList<GroupsModel> arrayOfList;
public static ListView listView;
public static String base_url = "myurl";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.two);
arrayOfList = new ArrayList<GroupsModel>();
listView = (ListView) findViewById(R.id.group_listview);
listView.setOnItemClickListener(this);
listView.setTextFilterEnabled(true);
new ProgressTask(two.this).execute();
}
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
#SuppressWarnings("unused")
private two activity;
public ProgressTask(two two) {
this.activity = two;
context = two;
dialog = new ProgressDialog(context);
}
private Context context;
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
grpAdapter = new GroupAdapter(two.this, R.layout.two_row,arrayOfList);
listView.setAdapter(grpAdapter);
}
protected Boolean doInBackground(final String... args) {
//arrayOfList = new ArrayList<GroupsModel>();
List<NameValuePair> params = new ArrayList<NameValuePair>();
//params.add(new BasicNameValuePair("",""));
JSONParser jp = new JSONParser();
JSONArray groups_obj = jp.makeHttpRequest(base_url + "groups/all", "GET", params);
for (int i = 0; i < groups_obj.length(); i++) {
GroupsModel group = new GroupsModel();
try {
JSONObject grp = groups_obj.getJSONObject(i);
group.setGroupId(grp.getInt("id"));
group.setGroupname(grp.getString("name"));
arrayOfList.add(group);
}
catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
SearchManager searchManager = (SearchManager) getSystemService( Context.SEARCH_SERVICE );
SearchView searchView = (SearchView) menu.findItem(R.id.menu_item_search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setSubmitButtonEnabled(false);
searchView.setOnQueryTextListener(this);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onQueryTextChange(String newText)
{
// this is your adapter that will be filtered
if (TextUtils.isEmpty(newText))
{
listView.clearTextFilter();
}
grpAdapter.getFilter().filter(newText.toString());
return true;
}
#Override
public boolean onQueryTextSubmit(String query) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
// TODO Auto-generated method stub
view.setBackgroundColor(Color.CYAN);
}}
My adapter is:
public class GroupAdapter extends ArrayAdapter<GroupsModel> implements Filterable{
private Context activity;
private ArrayList<GroupsModel> items ;
private List<GroupsModel> arrayList;
private ArrayFilter mFilter;
private int resource;
public GroupAdapter(Activity act, int resource, ArrayList<GroupsModel> arrayList) {
super(act, resource, arrayList);
this.activity = act;
this.resource = resource;
this.items = new ArrayList<GroupsModel>();
this.items.addAll(arrayList);
this.arrayList = new ArrayList<GroupsModel>();
this.arrayList.addAll(arrayList);
}
public View getView(final int position, View convertView,final ViewGroup parent) {
final ViewHolder holder;
LayoutInflater inflater = ((Activity) activity).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(resource,parent, false);
holder = new ViewHolder();
holder.group_name = (TextView) convertView.findViewById(R.id.group_name);
holder.select = (TextView) convertView.findViewById(R.id.select);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
try{
GroupsModel groups = items.get(position);
holder.group_name.setText(groups.getGroupName());
}catch(Exception e){
e.printStackTrace();
}
holder.select.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
holder.select.setText("my new text");
}
});
return convertView;
}
public class ViewHolder {
public TextView group_name,select;
}
#Override
public int getCount() {
// Total count includes list items and ads.
return items.size();
}
#Override
public GroupsModel getItem(int position)
{
// TODO Auto-generated method stub
return items.get(position);
}
#Override
public long getItemId(int position)
{
// TODO Auto-generated method stub
return position;
}
#Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}
private class ArrayFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (arrayList == null) {
synchronized (this) {
arrayList = new ArrayList<GroupsModel>(items);
}
}
if (prefix == null || prefix.length() == 0) {
ArrayList<GroupsModel> list;
synchronized (this) {
list = new ArrayList<GroupsModel>(arrayList);
}
results.values = list;
results.count = list.size();
} else {
String prefixString = prefix.toString().toLowerCase();
ArrayList<GroupsModel> values;
synchronized (this) {
values = new ArrayList<GroupsModel>(arrayList);
}
final int count = values.size();
final ArrayList<GroupsModel> newValues = new ArrayList<GroupsModel>();
for (int i = 0; i < count; i++) {
final String value = values.get(i).getGroupName();
final String valueText = value.toLowerCase();
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(values.get(i));
} else {
final String[] words = valueText.split(" ");
final int wordCount = words.length;
// Start at index 0, in case valueText starts with space(s)
for (int k = 0; k < wordCount; k++) {
if (words[k].startsWith(prefixString)) {
newValues.add(values.get(i));
break;
}
}
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
items = (ArrayList<GroupsModel>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}}
I cant figure this out. Please help
You need to maintain the selected item in adapter and use it to change the text :
Adapter Code
private int selectedIndex;
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
final ViewHolder holder;
LayoutInflater inflater = ((Activity) activity).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(resource,parent, false);
holder = new ViewHolder();
holder.group_name = (TextView) convertView.findViewById(R.id.group_name);
holder.select = (TextView) convertView.findViewById(R.id.select);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(selectedIndex!= -1 && position == selectedIndex)
{
convert_view.setBackgroundColor(Color.CYAN);
holder.select.setText("selected");
}
else
{
convert_vie.wsetBackgroundColor(default_color);
holder.select.setText("Select");
}
//Your other code .....
return convertView ;
}
public void setSelectedIndex(position)
{
selectedIndex = position;
}
Now set the selectedIndex variable when a list item clicked.
public class MainActivity extends Activity implements OnItemClickListener
{
// Implemented onItemClickListener
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
adapter.setSelectedIndex(position);
}
}
You can add a member "checked" in GroupsModel, and initial it assign false;
In activity
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
final boolean isChecked = listView.getItem(position).isChecked();
listView.get(position).setChecked(!isChecked);
}
In getView() in adapter:
public View getView(...) {
...
if(getItem(position).isChecked()) {
// You must set root view in holder
holder.getBackground().setBackgroundColor(Color.CYAN);
}
...
}
Your problem is that Android is reusing your views, so when you scroll, the first view disappears and appears at the bottom with the same state.
What you need to do is everytime you check an item, you need to store de id/position of the item checked (maybe ArrayList<Integer>), this way everytime your getView method is getting called you will look at this class/structure you have created and see it the row needs to be checked or not.
Note: If the row is not checked you will have to call to myCheck->setChecked(false); in order to assure that the row is in a coherent state.
You must use a array or option object to record which position is selected.
And detect the array or option object in getView() in adapter.
So, your need move the code: "view.setBackgroundColor(Color.CYAN)" to getView() method.
You have been bitten by what they say "recycling" issues.
When re-using your views, this kind of problems happens.
There are several methods(for example saving checked positions in an arraylist, ...) to deal with it, but in my opinion the simplest and straight forward solution is using tags.
setTag() and getTag()
Here is a tutorial using it.
Hope it helps.
Related
I have a list view which uses a base adapter, this is how I initialise it:
if (mBuses.size() < 1) {
// Initialising and loading data into adapter
mBuses = buses;
mBusesAdapter = new BusesArrayAdapter(BusesActivity.this, mBuses);
mBusesView.setAdapter(mBusesAdapter);
} else {
mBuses.addAll(buses);
mBusesAdapter.notifyDataSetChanged();
}
I am using a listener to check when the user scrolls to the bottom it fetches more data from the server the server and appends to the existing set instead of using pagination. It loads 100 items per page.
Now my problem is when I try to filter the data it always only filters the first 100 items, it does not include the other items.
This is my base adapter:
public class BusesArrayAdapter extends BaseAdapter implements Filterable {
private Context context;
private int altColour;
private ArrayList<BusModel> buses;
private BusModel bus;
private ValueFilter valueFilter;
private ArrayList<BusModel> filterList;
private static class ViewHolder{
RelativeLayout container;
TextView id;
TextView busType;
TextView registrationNo;
TextView vehicleModel;
TextView driverName;
TextView driverContact;
ImageButton btnEdit;
ImageButton btnRemove;
}
public BusesArrayAdapter(#NonNull Context context, #NonNull ArrayList<BusModel> buses) {
this.context = context;
this.buses = buses;
this.filterList = new ArrayList<>(buses);
}
#Override
public int getCount() {
return buses.size();
}
#Override
public BusModel getItem(int position) {
return buses.get(position);
}
#Override
public long getItemId(int position) {
return getItem(position).getId();
}
public void remove(BusModel bus) {
buses.remove(bus);
}
#NonNull
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public View getView(final int position, View convertView, #NonNull ViewGroup parent) {
// Get the data item for this position
bus = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
final ViewHolder viewHolder; // view lookup cache stored in tag
if (convertView == null) {
// If there's no view to re-use, inflate a brand new view for row
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.row_buses, parent, false);
viewHolder.container = (RelativeLayout) convertView.findViewById(R.id.row_buses_ll_container);
viewHolder.id = (TextView) convertView.findViewById(R.id.row_buses_tv_id);
viewHolder.busType = (TextView) convertView.findViewById(R.id.row_buses_tv_bus_type);
viewHolder.registrationNo = (TextView) convertView.findViewById(R.id.row_buses_tv_registration_no);
viewHolder.vehicleModel = (TextView) convertView.findViewById(R.id.row_buses_tv_vehicle_model);
viewHolder.driverName = (TextView) convertView.findViewById(R.id.row_buses_tv_driver_name);
viewHolder.driverContact = (TextView) convertView.findViewById(R.id.row_buses_tv_driver_contact);
viewHolder.btnEdit = (ImageButton) convertView.findViewById(R.id.row_buses_btn_edit);
viewHolder.btnEdit.setTag(position);
viewHolder.btnRemove = (ImageButton) convertView.findViewById(R.id.row_buses_btn_trash);
viewHolder.btnRemove.setTag(position);
// Cache the viewHolder object inside the fresh view
convertView.setTag(viewHolder);
} else {
// View is being recycled, retrieve the viewHolder object from tag
viewHolder = (ViewHolder) convertView.getTag();
}
// Populate the data from the data object via the viewHolder object
// into the template view.
if (altColour == 0) {
viewHolder.container.setBackgroundColor(Color.parseColor("#FFFFFF"));
altColour = 1;
} else {
viewHolder.container.setBackgroundColor(Color.parseColor("#EFEFEF"));
altColour = 0;
}
viewHolder.id.setText(String.valueOf(bus.getId()));
viewHolder.busType.setText(bus.getBusType());
viewHolder.registrationNo.setText(bus.getRegistrationNo());
viewHolder.vehicleModel.setText(bus.getVehicleModel());
viewHolder.driverName.setText(bus.getDriverName());
viewHolder.driverContact.setText(bus.getDriverContact());
viewHolder.btnEdit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = Integer.parseInt(viewHolder.btnRemove.getTag().toString());
BusModel bus = getItem(position);
if (bus != null) {
Intent editBusIntent = new Intent(context, EditBusActivity.class);
editBusIntent.putExtra("bus", bus);
((Activity) context).startActivityForResult(editBusIntent, 200);
}
}
});
viewHolder.btnRemove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = Integer.parseInt(viewHolder.btnRemove.getTag().toString());
removeBus(position);
}
});
// Return the completed view to render on screen
return convertView;
}
private void removeBus(final int position) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Confirm");
builder.setMessage("Are you sure you want to delete this item?");
builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
BusesRequest busesRequest = new BusesRequest(context);
busesRequest.remove(getItem(position).getId(), mTrashOnSuccessListener, mTrashOnErrorListener);
remove(getItem(position));
notifyDataSetChanged();
}
});
builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// Do nothing
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
private Response.Listener<JSONObject> mTrashOnSuccessListener = new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//
}
};
Response.ErrorListener mTrashOnErrorListener = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Utils.showNetworkResponse(context, error);
}
};
#Override
public Filter getFilter() {
// TODO Auto-generated method stub
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
//Invoked in a worker thread to filter the data according to the constraint.
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if(constraint != null && constraint.length() > 0){
ArrayList<BusModel> filterList = new ArrayList<BusModel>();
for(int i = 0; i < BusesArrayAdapter.this.filterList.size(); i++)
{
BusModel bus = BusesArrayAdapter.this.filterList.get(i);
if((bus.getRegistrationNo().toLowerCase())
.contains(constraint.toString().toLowerCase())
|| (bus.getDriverName().toLowerCase())
.contains(constraint.toString().toLowerCase()) ) {
filterList.add(new BusModel(
bus.getId(),
bus.getBusType(),
bus.getRegistrationNo(),
bus.getVehicleModel(),
bus.getDriverName(),
bus.getDriverContact()
));
}
}
results.count = filterList.size();
results.values = filterList;
} else{
results.count = filterList.size();
results.values = filterList;
}
return results;
}
//Invoked in the UI thread to publish the filtering results in the user interface.
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
buses = (ArrayList<BusModel>) results.values;
notifyDataSetChanged();
}
}
}
because filterList init only once while you are creating an instance of Adapter. you have to put new 100 items in filterList also.
this.filterList = new ArrayList<>(buses);
stores only 100 records when you are creating a new instance like this.
mBusesAdapter = new BusesArrayAdapter(BusesActivity.this, mBuses);
try to add every fetched items filterList also.
I have a listview getting filtered by an edit text on top.However when i click on the item searched i get the result of another item being selected. there r also some data stored in my array which is not visible on listview , is also returning wrong data.
On searching C you get the result filtered as C.But clicking on it results is like the position does not change for the other data but uses the original ArrayList adapter position.
Any help will be appreciated.
My items:
public class Leave_master_items {
public String leave_id;
public String leave_Name;
public String is_hourly;
public Leave_master_items(String leave_Name) {
this.leave_Name = leave_Name;
}
public String getLeave_id() {
return leave_id;
}
public void setLeave_id(String leave_id) {
this.leave_id = leave_id;
}
public String getLeave_Name() {
return leave_Name;
}
public void setLeave_Name(String leave_Name) {
this.leave_Name = leave_Name;
}
public String getIs_hourly() {
return is_hourly;
}
public void setIs_hourly(String is_hourly) {
this.is_hourly = is_hourly;
}
}
My Adapter:
public class Leave_name_adapter extends BaseAdapter implements Filterable{
ArrayList<Leave_master_items> cm = new ArrayList<>();
Context context;
ArrayList<Leave_master_items> mStringFilterList;
ValueFilter valueFilter;
#Override
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
// return null;
}
static class ListViewHolder {
TextView leaveType;
}
public Leave_name_adapter(ArrayList<Leave_master_items> cm, Context context) {
this.cm = cm;
this.context = context;
mStringFilterList = cm;
}
#Override
public int getCount() {
return cm.size();
}
#Override
public Object getItem(int position) {
return cm.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ListViewHolder viewHolder;
if (row == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.leaves_listview, parent, false);
viewHolder = new ListViewHolder();
viewHolder.leaveType = (TextView) row.findViewById(R.id.leavestype);
row.setTag(viewHolder);
} else {
viewHolder = (ListViewHolder) row.getTag();
}
Leave_master_items l = (Leave_master_items) getItem(position);
viewHolder.leaveType.setText(l.getLeave_Name());
return row;
}
private class ValueFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
// cm.clear();
if (constraint != null && constraint.length() > 0) {
ArrayList<Leave_master_items> filterList = new ArrayList<Leave_master_items>();
for (int i = 0; i < mStringFilterList.size(); i++) {
if ((mStringFilterList.get(i).getLeave_Name().toUpperCase())
.contains(constraint.toString().toUpperCase())) {
Leave_master_items country = new Leave_master_items(mStringFilterList.get(i).getLeave_Name());
filterList.add(country);
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = mStringFilterList.size();
results.values = mStringFilterList;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
cm = (ArrayList<Leave_master_items>) results.values;
notifyDataSetChanged();
}
}
}
My activity:
leave_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Leave_list().execute();
a.setVisibility(View.INVISIBLE);
b.setVisibility(View.VISIBLE);
v.setBackgroundResource(R.drawable.date_button_bg);
date.setBackgroundResource(R.drawable.leave_button_bg);
leave_btn.setTextColor(Color.parseColor("#293038"));
date.setTextColor(Color.parseColor("#F8F8F8"));
search_leave.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
Leave_application.this.leave_name_adapter.getFilter().filter(arg0);
}
#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
}
});
}
});
private class Leave_list extends AsyncTask<String, Void, Boolean> {
protected void onPreExecute() {
leave_master_itemses.clear();
}
#Override
protected void onPostExecute(final Boolean success) {
leave_name_adapter=new Leave_name_adapter(leave_master_itemses,getApplicationContext());
listview_leave.setAdapter(leave_name_adapter);
listview_leave.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Object a = parent.getAdapter().getItem(position);
String b = (String) parent.getItemAtPosition(position);
Leave_master_items leave_master_items=leave_master_itemses.get(position);
selectedFromList=leave_master_items.getLeave_id();
Log.d("Yourtag", selectedFromList);
// Log.d("Clicked item field", " "+ item.getColum(your colum index));
}
});
}
protected Boolean doInBackground(final String... args) {
try {
Login_json_parser jParser = new Login_json_parser();
String s = session.isWEBURL()+"?Function=" + session.isKEY_USERNAME() + "&Emp=" + session.iskey_emp_id();
Log.d("s", s);
JSONObject json1 = jParser.getJSONFromUrl(s);
Log.d("Inputfdfdtsale Stream", "json1");
try {
JSONObject object = (JSONObject) new JSONTokener(json1.toString()).nextValue();
Leave = object.getString("Leave");
Log.d("ew", Leave);
JSONArray jsonArray = new JSONArray(Leave);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = new JSONObject();
jsonObject=jsonArray.getJSONObject(i);
Leave_master_items leave_master_items = new Leave_master_items(null);
leave_master_items.setIs_hourly(jsonObject.getString("is_hourly"));
leave_master_items.setLeave_id(jsonObject.getString("leave_id"));
leave_master_items.setLeave_Name(jsonObject.getString("leave_Name"));
leave_master_itemses.add(leave_master_items);
}
}
catch(JSONException e){
e.printStackTrace();
}
}
catch (Exception e1) {
e1.printStackTrace();
}
return null;
}
}
You have to ask the adapter to get the right object.
Instead of
Leave_master_items leave_master_items = leave_master_itemses.get(position);
try
Leave_master_items leave_master_items = listview_leave.getAdapter().getItem(position);
UPDATE
When you filter you don't have to create a new object with the same content. Just use the object which already exist.
Instead of
Leave_master_items country = new Leave_master_items(mStringFilterList.get(i).getLeave_Name());
filterList.add(country);
Do
filterList.add(mStringFilterList.get(i));
UPDATE2
Don't return 0 in getItemId()
#Override
public long getItemId(int position) {
return position;
}
The problem here is as soon as you start searching something in edittext, your list content changes and you might be using the old list to get the item.
Create a setter in your adapter class for the list you just got after filtering and use that list in your onItemCLick to fetch the position you want to fetch.
I have created a list view in android and implemented custom filtering method, but images in the list view are not corresponding to text after using filter. This is because it filters only namesList list. I need to filter both namesList and imagesList at the same time. How do I do that?
public class MyCustomList extends ArrayAdapter<String> implements Filterable {
private final Activity context;
private List<String> filterList;
private List<String> namesList;
private List<String> imagesList;
public CustomList(Activity context,List<String> namesList, List<String> imagesList) {
super(context, R.layout.list_single, namesList);
this.context = context;
this.namesList = namesList;
this.imagesList = imagesList;
this.filterList= namesList;
}
#Override
public int getCount(){
return namesList.size();
}
#Override
public String getItem(int pos){
return namesList.get(pos);
}
#Override
public long getItemId(int pos){
return namesList.indexOf(getItem(pos));
}
#Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.list_single, null, true);
TextView txtTitle = (TextView) rowView.findViewById(R.id.txt);
ImageView imageView = (ImageView) rowView.findViewById(R.id.img);
txtTitle.setText(namesList.get(position));
imageView.setImageResource(context.getResources().getIdentifier(imagesList.get(position), "drawable", context.getPackageName()));
return rowView;
}
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
namesList = (List<String>) results.values;
notifyDataSetChanged();
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
namesList = filterList;
FilterResults results = new FilterResults();
if(constraint != null && constraint.length()>0){
List<String> FilteredArrayNames = new ArrayList <String>();
constraint = constraint.toString().toLowerCase();
for (int i = 0; i <namesList.size(); i++) {
String dataNames = namesList.get(i);
if (dataNames.toLowerCase().contains(constraint.toString())) {
FilteredArrayNames.add(dataNames);
}
}
results.count = FilteredArrayNames.size();
results.values = FilteredArrayNames;
Log.e("VALUES", results.values.toString());
} else {
results.count = namesList.size();
results.values = namesList;
}
return results;
}
};
return filter;
}
}
Modify your code with this:
List<String> FilteredArrayNames = new ArrayList <String>();
List<String> FilteredArrayImages = new ArrayList <String>();
constraint = constraint.toString().toLowerCase();
for (int i = 0; i <namesList.size(); i++) {
String dataNames = namesList.get(i);
String images = imagesList.get(i);
if (dataNames.toLowerCase().contains(constraint.toString())) {
FilteredArrayNames.add(dataNames);
FilteredArrayImages.add(images);
}
}
Then return this two List as a FilterResults object.
Try this example
Working for me
MainActivity
public class SearchActivity extends AppCompatActivity {
private ListView listView;
private MyAppAdapter myAppAdapter;
private ArrayList<Post> postArrayList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
listView = (ListView) findViewById(R.id.listView);
postArrayList = new ArrayList<>();
postArrayList.add(new Post("Dummy Title", "Dummy Sub Title"));
postArrayList.add(new Post("Searchview in actionbar", "enjoy search functionality from actionbar in android"));
postArrayList.add(new Post("Search in listview", "search feature that filter listview item"));
postArrayList.add(new Post("Android Search Bar", "adding search feature in toolbar using appcompat library"));
postArrayList.add(new Post("Android Studio SearchView example", "Android SearchView tutorial in android studio"));
postArrayList.add(new Post("Android Tutorial", "Get latest android material with simple solution"));
postArrayList.add(new Post("nkDroid tutorials", "A to Z Android tutorials at one place"));
myAppAdapter = new MyAppAdapter(postArrayList, SearchActivity.this);
listView.setAdapter(myAppAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_search, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
//*** setOnQueryTextFocusChangeListener ***
searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String searchQuery) {
myAppAdapter.filter(searchQuery.toString().trim());
listView.invalidate();
return true;
}
});
MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Do something when collapsed
return true; // Return true to collapse action view
}
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
// Do something when expanded
return true; // Return true to expand action view
}
});
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_search) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Adapter Example
public class MyAppAdapter extends BaseAdapter {
public class ViewHolder {
TextView txtTitle, txtSubTitle;
}
public List<Post> parkingList;
public Context context;
ArrayList<Post> arraylist;
public MyAppAdapter(List<Post> apps, Context context) {
this.parkingList = apps;
this.context = context;
arraylist = new ArrayList<Post>();
arraylist.addAll(parkingList);
}
#Override
public int getCount() {
return parkingList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View rowView = convertView;
ViewHolder viewHolder;
if (rowView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.item_post, null);
// configure view holder
viewHolder = new ViewHolder();
viewHolder.txtTitle = (TextView) rowView.findViewById(R.id.title);
viewHolder.txtSubTitle = (TextView) rowView.findViewById(R.id.subtitle);
rowView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.txtTitle.setText(parkingList.get(position).getPostTitle() + "");
viewHolder.txtSubTitle.setText(parkingList.get(position).getPostSubTitle() + "");
return rowView;
}
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
parkingList.clear();
if (charText.length() == 0) {
parkingList.addAll(arraylist);
} else {
for (Post postDetail : arraylist) {
if (charText.length() != 0 && postDetail.getPostTitle().toLowerCase(Locale.getDefault()).contains(charText)) {
parkingList.add(postDetail);
}
}
}
notifyDataSetChanged();
}
}
Post
public class Post {
private String postTitle;
private String postSubTitle;
public String getPostTitle() {
return postTitle;
}
public void setPostTitle(String postTitle) {
this.postTitle = postTitle;
}
public String getPostSubTitle() {
return postSubTitle;
}
public void setPostSubTitle(String postSubTitle) {
this.postSubTitle = postSubTitle;
}
public Post(String postTitle, String postSubTitle) {
this.postTitle = postTitle;
this.postSubTitle = postSubTitle;
}
}
every one! I am a new bie in android...In my app after clicking the button on fragment I switch to new Activity which shows the list then I filtered the list and now I want to get details of selected filtered list item back to calling fragment...I tried for onClick Listener in the getView method of adapter class which extends base adapter but it not switch to calling fragment..it remains there only
My Adapter classs
public class user_list_Adapter extends BaseAdapter {
private Context context;
public static ArrayList<user_list_item> user_arraylist;
private ArrayList<user_list_item> arraylist;
public static String selected_code;
public user_list_Adapter(Context context, ArrayList<user_list_item> user_array) {
this.context = context;
this.user_arraylist = user_array;
this.arraylist = new ArrayList<user_list_item>();
this.arraylist.addAll(user_array);
}
#Override
public int getCount() {
return user_arraylist.size();
}
#Override
public Object getItem(int position) {
return user_arraylist.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.user_row, null);
}
TextView txtname = (TextView) convertView.findViewById(R.id.dname);
TextView txtcode = (TextView) convertView.findViewById(R.id.dcode);
txtname.setText(user_arraylist.get(position).getCust_name());
txtcode.setText(user_arraylist.get(position).getCode());
// Listen for ListView Item Click
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Deposite df = new Deposite();
MainActivity activity = (MainActivity) context; //this line gives class cast exception
FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
Bundle b = new Bundle();
b.putString("search_name ", search_name);
b.putString("search_code ", search_code);
df.setArguments(b);
transaction.replace(R.id.content_frame, df);
transaction.addToBackStack(null);
transaction.commit();
}
});
return convertView;
}
// Filter Class
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
user_arraylist.clear();
if (charText.length() == 0) {
user_arraylist.addAll(arraylist);
}
else
{
for (user_list_item item : arraylist)
{
if (item.getCust_name().toLowerCase(Locale.getDefault()).contains(charText))
{
user_arraylist.add(item);
}
if (item.getCode().toLowerCase(Locale.getDefault()).contains(charText))
{
user_arraylist.add(item);
}
}
}
notifyDataSetChanged();
}
}
My Adpater class with inner class filter
public class user_list_Adapter extends ArrayAdapter<user_list_item> implements Filterable
{
private Filter mfilter;
private Context context;
private ArrayList<user_list_item> filter_user_list;
private ArrayList<user_list_item> alluserlist;
//public static String selected_code;
public user_list_Adapter(Context context, ArrayList<user_list_item> user_array) {
super(context,R.layout.user_row,user_array);
this.context = context;
this.filter_user_list = user_array;
this.alluserlist = new ArrayList<user_list_item>();
this.alluserlist.addAll(user_array);
}
#Override
public int getCount() {
return filter_user_list.size();
}
#Override
public user_list_item getItem(int position) {
return filter_user_list.get(position);
}
#Override
public long getItemId(int position) {
return filter_user_list.get(position).hashCode();
}
public void resetData() {
filter_user_list = alluserlist;
}
/* *********************************
* We use the holder pattern
* It makes the view faster and avoid finding the component
* **********************************/
private static class UserHolder {
public TextView txtname;
public TextView txtcode;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
UserHolder uholder=new UserHolder();
// First let's verify the convertView is not null
if (convertView == null) {
// This a new view we inflate the new layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.user_row, null);
// Now we can fill the layout with the right values
TextView tvname = (TextView) convertView.findViewById(R.id.dname);
TextView tvcode = (TextView) convertView.findViewById(R.id.dcode);
uholder.txtname = tvname;
uholder.txtcode = tvcode;
convertView.setTag(uholder);
}
else
uholder = (UserHolder) convertView.getTag();
user_list_item p = filter_user_list.get(position);
uholder.txtname.setText(p.getCust_name());
uholder.txtcode.setText(p.getCode());
return convertView;
}
/*
* We create our filter
*/
#Override
public Filter getFilter() {
if (mfilter == null)
mfilter = new userFilter();
return mfilter;
}
private class userFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence charText) {
FilterResults results = new FilterResults();
// We implement here the filter logic
if (charText == null || charText.length() == 0) {
// No filter implemented we return all the list
results.values = alluserlist;
results.count = alluserlist.size();
}
else {
// We perform filtering operation
List<user_list_item> uList = new ArrayList<user_list_item>();
for (user_list_item p : filter_user_list) {
if (p.getCust_name().toLowerCase(Locale.getDefault()).contains(charText)) {
uList.add(p);
}
if (p.getCode().toLowerCase(Locale.getDefault()).contains(charText)) {
uList.add(p);
}
}
results.values = uList;
results.count = uList.size();
}
return results;
}
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
// Now we have to inform the adapter about the new list filtered
if (results.count == 0)
notifyDataSetInvalidated();
else {
filter_user_list = (ArrayList<user_list_item>) results.values;
notifyDataSetChanged();
}
}
}
}
In My search_window Activity class ie.List class which calls adapter class
set onItemclick listener as
// Binds the Adapter to the ListView
list.setAdapter(adapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
// We know that each row in the adapter is a Map
user_list_item row = adapter.getItem(position);
//Toast.makeText(getApplicationContext(),"You Clicked On.."+row.getCust_name(),Toast.LENGTH_LONG).show();
MainActivity.deposite_search_flag = true; //global static variable
MainActivity.search_name = row.getCust_name(); //global
MainActivity.search_code =row.getCode(); //global
for (int i=0;i<RecordList.size();i++){ //user_list_item only contains name n code
if (row.getCode()==Code_Array[i]){
MainActivity.search_available = avail_bal_Array[i];
}
}
finish(); //switch to caller fragment and executes OnResume method of fragment
}
});
by setting global variables on MainActivity class I switched to caller fragment by directly finishing this activity(finish();)
//In caller fragment class
#Override
public void onResume() {
super.onResume();
if (MainActivity.deposite_search_flag){
txtname.setText(MainActivity.search_name);
txtcode.setText(MainActivity.search_code);
txt_available_bal.setText(MainActivity.search_available);
}
}
I have a very strange problem while using my ListView.
Only a part of my adapter items are renderd in the listview on screen but when I interact with the listview (ie tries to scroll it) all items are renderd properly.
This fenonemon only occurs if i have less items than the screen can show. Take a look at these screenshots below.
Before interaction:
After interaction:
Source code of activity where adding items:
String[] jRests = getResources().getStringArray(R.array.j_restaurants);
String[] lRests = getResources().getStringArray(R.array.l_restaurants);
items = new ArrayList<Object>();
items.add(getString(R.string.campus_j));
for(String item : jRests){
String[] val = item.split(",,,");
items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
}
items.add(getString(R.string.campus_l));
for(String item : lRests){
String[] val = item.split(",,,");
items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
adapter = new BaseSectionAdapter(this, R.layout.list_item_fragment_header);
if(!isTabletView()){
adapter.setSelectedItem(-1);
}
adapter.setItems(items);
Code of adapter:
public class BaseSectionAdapter extends AmazingAdapter {
private LayoutInflater inflater;
private int selectedItem = 0;
private List<Object> items;
private List<SectionItem> sections = new ArrayList<SectionItem>(10);
private List<Class> itemTypes = new ArrayList<Class>();
private List<Integer> sectionPositions = new ArrayList<Integer>();
private int listHeaderLayoutId;
private View headerView;
public static interface ISectionListItem {
public void setProps(View convertView, int position, int selectedItem);
public View getLayout(LayoutInflater inflater);
}
private class SectionItem implements Serializable {
private static final long serialVersionUID = -8930010937740160935L;
String text;
int position;
public SectionItem(String text, int position) {
this.text = text;
this.position = position;
}
}
public BaseSectionAdapter(Context context, int listHeaderLayoutId) {
this.listHeaderLayoutId = listHeaderLayoutId;
init(context);
}
public BaseSectionAdapter(Context context, int listHeaderLayoutId, List<Object> listItems) {
this.listHeaderLayoutId = listHeaderLayoutId;
init(context);
initListItems(listItems);
}
private void init(Context context) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setSelectedItem(int position) {
selectedItem = position;
}
// public List<ListItem> getItems() {
// return items;
// }
private void initListItems(List<Object> itemList) {
int curSection = -1;
//int curPosition = 0;
//curSection = 0;
this.items = itemList;
itemTypes.clear();
sections.clear();
sectionPositions.clear();
int listSize = itemList.size();
for(int i = 0; i < listSize; i++){
Object currentItem = items.get(i);
if(currentItem instanceof String){
sections.add(new SectionItem((String) currentItem,i));
curSection++;
}
if(!itemTypes.contains(currentItem.getClass())){
itemTypes.add(currentItem.getClass());
}
sectionPositions.add(curSection);
}
Log.d("test", "No of items = "+items.size());
Log.d("test", "No of itemtypes = "+itemTypes.size());
Log.d("test", "View type count = "+getViewTypeCount());
}
public void setItems(List<Object> itemList) {
initListItems(itemList);
}
public int getCount() {
return items==null?0:items.size();
}
#Override
public int getViewTypeCount(){
return (itemTypes.size() == 0)?1:itemTypes.size();
}
#Override
public int getItemViewType(int position){
return itemTypes.indexOf(items.get(position).getClass());
}
#Override
public boolean isEnabled(int position){
return !(items.get(position) instanceof String || items.get(position) instanceof EmptySectionListItem);
}
#Override
public Object getItem(int position) {
return items.get(position);
}
public long getItemId(int position) {
return position;
}
#Override
protected void onNextPageRequested(int page) {
// TODO Auto-generated method stub
}
#Override
protected void bindSectionHeader(View view, int position,
boolean displaySectionHeader) {
// TextView lSectionTitle = (TextView) view
// .findViewById(R.id.txt_list_header);
// if (displaySectionHeader) {
// lSectionTitle.setVisibility(View.VISIBLE);
// lSectionTitle
// .setText(getSections()[getSectionForPosition(position)]);
// } else {
// lSectionTitle.setVisibility(View.GONE);
// }
}
#Override
public View getAmazingView(int position, View convertView, ViewGroup parent) {
Object curItemObject = items.get(position);
boolean isHeader = (curItemObject instanceof String);
if(convertView == null){
if(isHeader && headerView != null){
convertView = headerView;
}else if(isHeader){
convertView = inflater.inflate(listHeaderLayoutId, null);
headerView = convertView;
}else{
convertView = ((ISectionListItem) curItemObject).getLayout(inflater);
}
}
if(isHeader){
TextView header = ((TextView)convertView.findViewById(R.id.txt_list_header));
header.setText((String)curItemObject);
}else{
((ISectionListItem)curItemObject).setProps(convertView, position, selectedItem);
}
return convertView;
}
#Override
public void configurePinnedHeader(View header, int position, int alpha) {
TextView textView = ((TextView)header.findViewById(R.id.txt_list_header));
textView.setText(getSections()[getSectionForPosition(position)]);
}
#Override
public int getPositionForSection(int section) {
if(section >= sections.size()){
return 0;
}
return sections.get(section).position;
}
#Override
public int getSectionForPosition(int position) {
return sectionPositions.get(position);
}
#Override
public String[] getSections() {
String[] res = new String[sections.size()];
for (int i = 0; i < res.length; i++) {
res[i] = sections.get(i).text;
}
return res;
}
}
Code of layout:
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.HORIZONTAL);
FrameLayout listLayout = new FrameLayout(this);
LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
listParams.weight = 1;
listLayout.setId(LIST_FRAGMENT_VIEW_ID);
FrameLayout detailLayout = new FrameLayout(this);
LinearLayout.LayoutParams detailParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
detailParams.weight = 2;
detailLayout.setId(DETAIL_FRAGMENT_VIEW_ID);
layout.addView(listLayout, listParams);
layout.addView(detailLayout, detailParams);
if(savedInstanceState == null){
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(listLayout.getId(), (Fragment) listFragment, TWO_PANEL_LIST_FRAGMENT_TAG);
ft.add(detailLayout.getId(), detailFragment);
ft.commit();
}
setContentView(layout);
try calling notifyDataSetChanged() in runOnUIThread() method like I have shown below and it will work like a charm. :)
runOnUiThread(new Runnable() {
#Override
public void run() {
messageAdapter.notifyDataSetChanged();
}
});
i dont know what causes the problem, but if you don't find a logical solution to it you could try something like this:
trigger an onTouchEvent() programmatically whenever you launch the ListView.
scroll down and back up programmatically as soon as the ListView is launched.
etc..
Add ListView widget to layout.xml and add content of list to that. Do not use FrameLayout as it probably is the cause of the problem. It is updating content after touch so the Layout it is on is no implementing the correct onCreate() setup as the ListView widget has.
Are you calling the method notifyDataSetChanged() on your adapter after adding new items? This causes the listview to refresh its view when the underlying dataset is changed.
If it still doesn't work, try notifyDataSetInvalidated() that causes the listview to redraw completely.
Solved it!!!
Problem was with the adapter trying to reuse the same section item. Not good!!!
Changed it to inflate the section item each time we hit a section!