I have been fighting with this problem for days. Looking for the solution on stackoverflow or anywhere a solution is given, tried all of them even tried recyclerView but nothing helped.
My PROBLEM is that I've a listview and two textView on a listItem. So whenever I click on list item, Visibility of one textView is GONE. But when I scroll down I see not only clicked one is gone but many others are gone as well.
Heres my code
CustomAdapter.java class
package com.example.nara.testtt;
import android.content.Context;
import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.
import java.util.ArrayList;
public class CustomAdapter extends BaseAdapter {
private ArrayList<String> list = new ArrayList<String>();
private Context context;
public CustomAdapter(Context context){
this.context = context;
for(int i = 0; i < 50; i++){
list.add("item at " + i);
}
}
#Override
public int getCount() {
return list.size();
}
#Override
public String getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if(convertView == null){
LayoutInflater inflator = LayoutInflater.from(context);
convertView = inflator.inflate(R.layout.list_item,null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else{
holder = (ViewHolder)convertView.getTag();
}
holder.tv1.setText(getItem(position));
holder.tv2.setText(getItem(position));
return convertView;
}
public static class ViewHolder{
private TextView tv1;
private TextView tv2;
public ViewHolder(View view){
tv1 = (TextView) view.findViewById(R.id.textView);
tv2 = (TextView) view.findViewById(R.id.textView2);
}
}
}
MainActivity.java
package com.example.nara.testtt;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
CustomAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter = new CustomAdapter(this);
ListView lv = (ListView) findViewById(R.id.listView);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TextView tv = (TextView) view.findViewById(R.id.textView);
tv.setVisibility(View.GONE);
adapter.notifyDataSetChanged();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
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_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
In getView() after setting the text update the visibility of the textview to Visible, since listitems in the ListView will get recycled.
holder.tv1.setText(getItem(position));
holder.tv2.setText(getItem(position));
holder.tv1.setVisibility(View.VISIBLE);
//Your code.....
Updated :
public class CustomAdapter extends BaseAdapter {
private ArrayList list = new ArrayList();
private Context context;
public CustomAdapter(Context context) {
this.context = context;
for (int i = 0; i < 50; i++) {
list.add(new Bean("item at " + i));
}
}
#Override
public Bean getItem(int position) {
return list.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//Initialization .......
Bean item = getItem(position);
holder.tv1.setText(item.name);
holder.tv2.setText(item.name);
holder.tv1.setVisibility(item.visibility);
return convertView;
}
// ViewHolder declaration
.......
public static class Bean {
String name;
int visibility = View.VISIBLE;
public Bean(String name) {
this.name = name;
}
}
In the onItemClick on your activity.
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TextView tv = (TextView) view.findViewById(R.id.textView);
Bean bean = Adapter.getItem(position);
bean.visibility = View.GONE
tv.setVisibility(View.GONE);
adapter.notifyDataSetChanged();
}
The problem is that the views are getting recycled in your adapter. So when you are scrolling the old views are getting used for the new ones. That means if the visibility of the items of the old view are set to GONE are still GONE in the new ones. If you dont want to save the visibility you can just set them to visible in your adapter:
holder.tv1.setVisibility(View.VISIBLE);
holder.tv1.setText(getItem(position));
holder.tv2.setText(getItem(position));
Or you store boolean values in a list or something like that and ask there if the item was clicked:
if(clicked.get(i)) holder.tv1.setVisibility(View.GONE);
else holder.tv1.setVisibility(View.VISIBLE);
Replace
convertView = inflator.inflate(R.layout.list_item,null);
with
convertView = inflator.inflate(R.layout.list_item,container,false);
Related
I am using a custom listview adapter to capture multiple objects of the same domain class Food. This class is:
public class Food {
public String Item;
public String Description;
public int count;
}
My custom Adapter is:
public class FoodAdapter extends ArrayAdapter<Food> {
private final Context context;
private final ArrayList<Food> itemsArrayList;
EditText item
EditText desc
EditText count;
public ArrayList<Food> getItemsArrayList() {
return itemsArrayList;
}
public FoodAdapter(Context context, ArrayList<Food> itemsArrayList) {
super(context, R.layout.fr_row, itemsArrayList);
//super(context, itemsArrayList);
this.context = context;
this.itemsArrayList = itemsArrayList;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// 1. Create inflater
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// 2. Get rowView from inflater
View rowView = inflater.inflate(R.layout.fr_row, parent, false);
// 3. Get the two text view from the rowView
item= (EditText) rowView.findViewById(R.id.f_item);
desc= (EditText) rowView.findViewById(R.id.f_desc);
count = (EditText) rowView.findViewById(R.id.f_count);
return rowView;
}
}
And my ActivityThat coordinates this listview is:
package com.example.foodie;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.telephony.TelephonyManager;
import android.view.View;
import android.widget.ListView;
public class FoodActivity extends AppCompatActivity {
ListView lv;
FoodAdapter adapter;
ArrayList<Food> fList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frmorning);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
setContentView(R.layout.activity_frmorning);
lv = (ListView) findViewById(R.id.list);
fList = new ArrayList<Food>();
adapter =new FoodAdapter(this, fList);
lv.setAdapter(adapter);
}
public void addItems(View v) {
fList.add(new Food());
adapter.notifyDataSetChanged();
}
}
This addItems is a button on the layout (in FoodActivity). When I tap on the add, I get the new row. But, the rows lose all content after the new row is added. They all are blank. What is causing this behaviour and how to solve? Also, how can I bind the EditText fields to the data in the ArrayList, so that when I call getItemsArrayList() I get the correct ArrayList that corresponds to the screen display?
When you are not using Holder so getView() method will call findViewById() as many times as you row(s) will be out of View. So if you have 1000 rows in List and 990 rows will be out of View then 990 times will be called findViewById() again.
Holder design pattern is used for View caching - Holder (arbitrary) object holds child widgets of each row and when row is out of View then findViewById() won't be called but View will be recycled and widgets will be obtained from Holder.
public class FoodAdapter extends ArrayAdapter<Food>
{
private final Context context;
private final ArrayList<Food> itemsArrayList;
public FoodAdapter(Context context, ArrayList<Food> itemsArrayList) {
{
super(context, itemsArrayList);
this.context = context;
this.itemsArrayList = itemsArrayList;
}
#Override
public int getCount()
{
return itemsArrayList.size();
}
#Override
public Object getItem(int position)
{
return itemsArrayList.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null)
{
holder = new ViewHolder();
LayoutInflater inflater=(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.fr_row, parent, false);
holder.text = (EditText ) convertView.findViewById(R.id.edittext);
convertView.setTag(holder);
} else
{
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(itemsArrayList.get(position));
return convertView;
}
class ViewHolder
{
EditText item
EditText desc
EditText count;
}
}`enter code here`
I have a RecyclerView that holds a bunch of cards (fetches data from the web, then populates cards). I have the cards forming properly after data is fetched, but now I would now like the set a listener for when each card is clicked. Ideally, after each card is clicked, a new intent will be called with further details about that card's data.
Here is where I initialize the adapter. arrList is an ArrayList that has already been filled from another class
private void initializeAdapter() {
RecycleViewAdapter adapter = new RecycleViewAdapter(arrList);
rv.setAdapter(adapter);
}
This is another class that holds the cards:
public class PersonViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
CardView cv;
TextView crimeName,crimeID, crimeAddress, crimeDate, crimeWeapon;
ImageView crimePhoto;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
crimeName = (TextView) itemView.findViewById(R.id.crime_name);
crimeID = (TextView) itemView.findViewById(R.id.crime_id);
crimeAddress = (TextView) itemView.findViewById(R.id.crime_address);
crimeDate = (TextView) itemView.findViewById(R.id.crime_date);
crimeWeapon = (TextView) itemView.findViewById(R.id.crime_weapon);
crimePhoto = (ImageView)itemView.findViewById(R.id.crime_photo);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
// WHAT DO I CALL HERE TO GET THE INDEX OF THE ITEM CLICKED ON ?? //
Log.d("app", "clicked");
}
}
the onClick from above should go to this class (by an intent) and pass the index along with it:
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
public class CrimeDetails extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime_details);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.crime_details, menu);
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_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_crime_details, container, false);
return rootView;
}
}
}
How can I get the Clicked Position of the Card ?
Thanks
Do net set the onClickListener in your onCreateVH method but in onBindViewHolder
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((PersonViewHolder)holder).yourRootLayout.setOnClickListener(getPersonClickListener(position));
}
View.OnClickListener getPersonClickListener(final int position) {
return new View.OnClickListener() {
#Override
public void onClick(View view) {
//TODO whatever you want with position
}
};
}
EDIT:
tyczj is right. Binding the Clicklistener in the onBindViewHolder is a very easy but maybe not the best Solution - however it will work!
Another way is to use the getAdapterPosition() method from Viewholder itself and bind it in the onCreateViewHolder:
#Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.yourLayoutXml, parent, false);
final ViewHolder holder = new PersonViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final int position = holder.getAdapterPosition();
//check if position exists
if (position != RecyclerView.NO_POSITION) {
//TODO whatever you want
}
}
});
return holder;
}
you use getAdapterPosition() in your ViewHolder
I am doing this slightly different, using a different onClick call, then I can use the
getAdapterPosition()
method to determine which item was clicked.
public static class MyViewHolder extends RecyclerView.ViewHolder {
...
RelativeLayout myLayout = (RelativeLayout) v.findViewById(R.id.device_adap_layout);
myLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Context cxt = myLayout.getContext();
final Intent i = new Intent(cxt, NextActivity.class);
i.putExtra("ITEMNAME", mAdapterList.get(getAdapterPosition()));
cxt.startActivity(i, options.toBundle());
}
});
...
}
Create adapter class which extend Recycle view and override needed method:
public class Adapter extends RecyclerView.Adapter
"<"Adapter.AdapterViewHolder">" {
public List<Object> Items;
private Context context;
public Adapter(List<Object> items, Context context) {
Items = items;
this.context = context;
}
#Override
public int getItemCount() {
return comentsItems.size();
}
#Override
public void onBindViewHolder(final AdapterViewHolder hd, int position) {
int indexOfCard = position;
hd.itemText.setText("pos: "+ position);
}
#Override
public AdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.
from(viewGroup.getContext()).
inflate(R.layout.item_layout, viewGroup, false);
return new AdapterViewHolder(itemView);
}
public static class AdapterViewHolder extends RecyclerView.ViewHolder {
protected TextView itemText;
public AdapterViewHolder(View v) {
super(v);
itemText = (TextView)v.findViewById(R.id. itemText);
}
}
}
You should set the onClickListener in onBindViewHolder where you already have the position:
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
listener.onItemSelected(position);
}
}
});
}
EDIT:
Like #tyczj says, for the RecyclerView it's better to use getAdapterPosition in ViewHolder.
When you populate the cardView with your data, you can also use the View's setTag() method to store the position. Since you will get the View when onClick is called, you can simply call getTag() on the View to retrieve the position.
I've a problem with listview in android, I've created a list view that takes data from SQLite database with a custom ArrayAdapter
I want to display an image view when user choose an item, but when I click on an item, the image (check mark) shows in 3 other items
I don't know where is the problem exactly, here is my code for adapter :
import info.androidhive.tabsswipe.R;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.itdinamik.tabswipe.CompareVehicle;
import com.itdinamik.vcompare.MySQLiteHelper;
import com.itdinamik.vcompare.Vehicle;
public class ComperAdapter extends ArrayAdapter<Vehicle>{
List<Vehicle> data;
Context context;
int layoutResID;
Vehicle itemdata;
MySQLiteHelper dbhelper;
public ComperAdapter(Context context, int layoutResourceId, List<Vehicle> data) {
super(context, layoutResourceId, data);
this.data=data;
this.context=context;
this.layoutResID=layoutResourceId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final NewsHolder holder;
View row = convertView;
dbhelper = new MySQLiteHelper(context);
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResID, parent, false);
holder = new NewsHolder();
holder.itemNameTitle = (TextView)row.findViewById(R.id.VehicleTxt);
holder.itemNameScore = (TextView)row.findViewById(R.id.Score);
holder.CheckedMark=(ImageView)row.findViewById(R.id.Checked);
holder.Vehicle=(ImageView)row.findViewById(R.id.Vehicle);
holder.RL = (RelativeLayout)row.findViewById(R.id.Rv);
row.setTag(holder);
}
else
{
holder = (NewsHolder)row.getTag();
}
//Toast.makeText(getContext(), String.valueOf(position +" - " + CompareVehicle.ClickedItem), Toast.LENGTH_SHORT).show();
if(CompareVehicle.ItemClieckd) {
if(position == CompareVehicle.ClickedItem) {
Log.w("Position", String.valueOf(position));
holder.CheckedMark.setVisibility(View.VISIBLE);
holder.RL.setBackgroundColor(Color.rgb(201, 50, 39));
}
}
itemdata = data.get(position);
holder.itemNameTitle.setText(itemdata.getTitle() + " - " + itemdata.getKraj() + " - "+ String.valueOf(position) + " - " + CompareVehicle.ClickedItem);
double totaldefault = itemdata.getOhranjenost()*0.25+itemdata.getPrevozeni()*0.16+
itemdata.getServis()*0.14+ itemdata.getCena()*0.13+
itemdata.getPoraba()*0.11+ itemdata.getStarost()*0.08+
itemdata.getDodatna()*0.07+ itemdata.getCenaZav()*0.06;
holder.itemNameScore.setText(String.format("%.1f",totaldefault));
return row;
}
static class NewsHolder{
TextView itemNameTitle;
TextView itemNameScore;
ImageView CheckedMark, Vehicle;
RelativeLayout RL;
}
}
and this one is for my fragment that i use to show my list view
import info.androidhive.tabsswipe.R;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.itdinamik.tabswipe.adapter.ComperAdapter;
import com.itdinamik.vcompare.MySQLiteHelper;
import com.itdinamik.vcompare.Vehicle;
public class CompareVehicle extends Fragment{
ViewPager mViewPager;
ArrayList<Vehicle> DataList;
static MySQLiteHelper dbhelper;
ComperAdapter adapter;
List<Vehicle> itemData;
ListView lv;
Button CompareButton;
int ClickedNum = 0;
public static int ClickedItem;
public static boolean ItemClieckd = false;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_compare_vehicle, container, false);
lv = (ListView)rootView.findViewById(R.id.CompareList);
CompareButton = (Button)rootView.findViewById(R.id.CompareButton);
dbhelper = new MySQLiteHelper(getActivity());
// get all vehicles
itemData = dbhelper.getAllVehicles();
adapter=new ComperAdapter(getActivity(),R.layout.list_single,itemData);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
// TODO Auto-generated method stub
ClickedItem = position;
ItemClieckd = true;
ClickedNum += 1;
adapter.notifyDataSetChanged();
/*RelativeLayout Rl = (RelativeLayout)arg1.findViewById(R.id.Rv);
ImageView CheckImg = (ImageView)arg1.findViewById(R.id.Checked);
Rl.setBackgroundColor(Color.rgb(201, 50, 39));
CheckImg.setVisibility(View.VISIBLE);*/
//Toast.makeText(getActivity(), String.valueOf(mSelectedItem), Toast.LENGTH_LONG).show();
}
});
CompareButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (ClickedNum < 2) {
Toast.makeText(getActivity(), "Please mark at least 2 items to compare them", Toast.LENGTH_LONG).show();
}
}
});
return rootView;
}
}
thank you
To avoid issues with view recycling in ListViews etc, I include a boolean for checked state in the item data List supplied to the constructor of the ArrayAdapter. I also provide my own interface for handling things like click events on child Views contained in my custom list item layout.
In my example below we handle a checkbox which can be clicked and also a label which can be long clicked:
public class MyListAdapter extends ArrayAdapter<MyItem> {
// interface for handling item child view events
public interface MyListAdapterListener {
void onItemCheckClicked(int index);
void onItemLabelLongClicked(int index);
}
private MyListAdapterListener mMyListAdapterListener;
int layoutResID;
// Constructor
public MyListAdapter(Context context, int resource, List<MyItem> myItems) {
super(context, resource, myItems);
layoutResID = resource;
}
public void setMyListAdapterListener(MyListAdapterListener listener) {
this.mMyListAdapterListener = listener;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// setup the row
View row;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
row = inflater.inflate(layoutResID, null);
} else {
row = convertView;
}
// setup the ViewHolder for this item
ViewHolder holder = (ViewHolder) row.getTag();
if (holder == null) {
holder = new ViewHolder(row);
row.setTag(holder);
}
// setup this item's label view
holder.label.setText(getItem(position).label);
// tag this item's label view with position so it can be retrieved in the onLongClick
holder.label.setTag(position);
// set the OnLongClickListener for the this item's label view
holder.label.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mActivityListListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemLabelLongClicked method
mActivityListListener.onItemLabelLongClicked((Integer)v.getTag());
}
return false;
}
});
// setup this item's checkbox view
holder.checkbox.setChecked(getItem(position).myItemCheckBoolean);
// tag this item's checkbox view with position so it can be retrieved in the onClick
holder.checkbox.setTag(position);
// set the OnClickListener for the this item's checkbox view
holder.checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mMyListAdapterListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemCheckClicked method
mMyListAdapterListener.onItemCheckClicked((Integer) v.getTag());
}
}
});
return row;
}
class ViewHolder {
CheckBox checkbox = null;
TextView label = null;
ViewHolder(View row) {
this.checkbox = (CheckBox) row.findViewById(R.id.check_box);
this.label = (TextView) row.findViewById(R.id.item_label);
}
}
}
The MyItem class:
public class MyItem {
public String label;
public boolean myItemCheckBoolean;
}
Using the ArrayAdapter:
public class MyFragment extends Fragment {
....
private List<MyItem> myItems = new ArrayList<MyItem>();
....
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment__my_list, container, false);
lv = (ListView)rootView.findViewById(R.id.my_list);
// For example purposes, fill myItems with dummy data setting all checkboxes initially to false
for (int i = 0; i < 10; i++) {
MyItem myItem = new MyItem();
myItem.label = "Item " + i;
myItem.myItemCheckBoolean = false;
myItems.add(myItem);
}
MyListAdapter adapter = new MyListAdapter(getActivity(), R.layout.my_list_item, myItems);
adapter.setMyListAdapterListener( new MyListAdapter.MyListAdapterListener() {
#Override
public void onItemCheckClicked(int index) {
Log.d("MyFragment", "Item " + index + " Check Clicked");
// toggle the item's boolean
myItems.get(index).myItemCheckBoolean = !myItems.get(index).myItemCheckBoolean;
}
#Override
public void onItemLabelLongClicked(int index) {
Log.d("MyFragment", "Item " + index + " Label LongClicked");
}
}
lv.setAdapter(adapter);
....
return rootView;
}
Additional:
In response to your comment, you can use the adapter to customize the display of your list items as you wish. The version below shows how you might modify the adapter to use an ImageView instead of a CheckBox, and also changes the background color:
public class MyListAdapter extends ArrayAdapter<MyItem> {
// interface for handling item child view events
public interface MyListAdapterListener {
void onItemCheckClicked(int index);
void onItemLabelLongClicked(int index);
}
private MyListAdapterListener mMyListAdapterListener;
int layoutResID;
// Constructor
public MyListAdapter(Context context, int resource, List<MyItem> myItems) {
super(context, resource, myItems);
layoutResID = resource;
}
public void setMyListAdapterListener(MyListAdapterListener listener) {
this.mMyListAdapterListener = listener;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// setup the row
View row;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
row = inflater.inflate(layoutResID, null);
} else {
row = convertView;
}
// setup the ViewHolder for this item
ViewHolder holder = (ViewHolder) row.getTag();
if (holder == null) {
holder = new ViewHolder(row);
row.setTag(holder);
}
// setup this item's label view
holder.label.setText(getItem(position).label);
// tag this item's label view with position so it can be retrieved in the onLongClick
holder.label.setTag(position);
// set the OnLongClickListener for the this item's label view
holder.label.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mActivityListListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemLabelLongClicked method
mActivityListListener.onItemLabelLongClicked((Integer)v.getTag());
}
return false;
}
});
// setup this item's image view based on the current state of the boolean
if (getItem(position).myItemCheckBoolean) {
holder.image.setImageResource(R.drawable.image_a);
} else {
holder.image.setImageResource(R.drawable.image_b);
}
// tag this item's image view with position so it can be retrieved in the onClick
holder.image.setTag(position);
// set the OnClickListener for the this item's image view
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mMyListAdapterListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemCheckClicked method
mMyListAdapterListener.onItemCheckClicked((Integer) v.getTag());
}
}
});
// setup this item's background based on the current state of the boolean
if (getItem(position).myItemCheckBoolean) {
holder.layout.setBackgroundColor(Color.red);
} else {
holder.layout.setBackgroundColor(Color.white);
}
return row;
}
class ViewHolder {
ImageView image = null;
TextView label = null;
RelativeLayout layout = null;
// constructor
ViewHolder(View row) {
this.image = (ImageView) row.findViewById(R.id.item_image);
this.label = (TextView) row.findViewById(R.id.item_label);
this.layout = (RelativeLayout) row.findViewById(R.id.item_layout)
}
}
}
i have developed an application that have one list view and that list view's one item contain one image view one text view and one check box so my question is how to handle check box checked and unchecked event of particular list view item
Adapter class for list view
package com.rk.test_facebook;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class ListAdapter extends BaseAdapter {
private ArrayList<String> imageUrl;
private final ArrayList<String> name;
private final ArrayList<String> birthday;
private Activity activity;
private static LayoutInflater inflater = null;
public ImageLoader imageLoader;
public ListAdapter(Activity activity, ArrayList<String> imageUrl, ArrayList<String> birthday, ArrayList<String> name) {
this.activity = activity;
this.imageUrl = imageUrl;
this.name = name;
this.birthday = birthday;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return name.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null)
view = inflater.inflate(R.layout.listelement, null);
TextView text = (TextView) view.findViewById(R.id.text);
ImageView image = (ImageView) view.findViewById(R.id.image);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox);
text.setText((name.get(position)));
imageLoader.DisplayImage(imageUrl.get(position), image);
return view;
}
}
main activity
package com.rk.test_facebook;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import java.util.ArrayList;
import Handler.DatabaseHandler;
import Property.FriendsProperty;
/**
* Created by Intex on 15/04/2014.
*/
public class FriedsList extends Activity {
private ListView listView;
public static ArrayList<String> arrayListName = new ArrayList<String>();
public static ArrayList<String> arrayListBirthday = new ArrayList<String>();
public static ArrayList<String> arrayListImage = new ArrayList<String>();
private ListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.friendslist);
listView = (ListView) findViewById(R.id.ListView);
DatabaseHandler databaseHandler = new DatabaseHandler(this);
ArrayList<FriendsProperty> properties = databaseHandler.DislpayFriends();
for (FriendsProperty friendsProperty : properties) {
arrayListName.add(friendsProperty.getName());
arrayListImage.add(friendsProperty.getImage());
arrayListBirthday.add(friendsProperty.getBirthday());
}
databaseHandler.close();
adapter = new ListAdapter(this, arrayListImage, arrayListBirthday, arrayListName);
listView.setAdapter(adapter);
}
}
Change the code getView() call back as below,
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null)
view = inflater.inflate(R.layout.listelement, null);
TextView text = (TextView) view.findViewById(R.id.text);
ImageView image = (ImageView) view.findViewById(R.id.image);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox);
checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (isChecked) {
// it is check
} else {
// it is unchecked
}
}
});
text.setText((name.get(position)));
imageLoader.DisplayImage(imageUrl.get(position), image);
return view;
}
The method in the getView() you must add an setOnCheckedChangeListener as follows
checkBox.setOnCheckedChangeListener(starCheckedChangeListener);
}
private OnCheckedChangeListener starCheckedChangeListener = new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
if(isChecked)
{
//DO WHEN CHECKED
}
else
{
//Do when not checked
}
}
};
Change the code to below to add the checked item in array.
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null)
view = inflater.inflate(R.layout.listelement, null);
TextView text = (TextView) view.findViewById(R.id.text);
ImageView image = (ImageView) view.findViewById(R.id.image);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox);
checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (isChecked) {
selectedItemArrayList.add(dataArrayList.get(position));
} else {
selectedItemArrayList.remove(dataArrayList.get(position));
}
}
});
text.setText((name.get(position)));
imageLoader.DisplayImage(imageUrl.get(position), image);
return view;
}
Trying to create an app with an expandable list within a DrawerLayout. I had the DrawerLayout working fine with just pulling the list from an array in strings.xml.
Ever since I added the ExpandableListAdapter though it's been crashing, or even if it runs it just doesn't let me do anything.
Here's my code:
package com.alpha.omegaRSS;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ExpandableListView;
public class MainActivity extends Activity {
private DrawerLayout navDrawerLayout;
private ActionBarDrawerToggle navDrawerToggle;
//private ListView navDrawerList;
private CharSequence navDrawerTitle;
private CharSequence navTitle;
private String[] leftItems;
private ExpandableListView navDrawerList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
navTitle=navDrawerTitle=getTitle();
//leftItems = getResources().getStringArray(R.array.left_drawer_array);
navDrawerLayout=(DrawerLayout) findViewById(R.id.nav_layout);
//navDrawerList= (ListView) findViewById(R.id.left_drawer);
navDrawerList=(ExpandableListView)findViewById(R.id.left_drawer);
ArrayList<Parent> arrayParents = new ArrayList<Parent>();
ArrayList<String> arrayChildren = new ArrayList<String>();
//here we set the parents and the children
for (int i = 0; i < 10; i++){
//for each "i" create a new Parent object to set the title and the children
Parent parent = new Parent();
parent.setTitle("Parent " + i);
arrayChildren = new ArrayList<String>();
for (int j = 0; j < 10; j++) {
arrayChildren.add("Child " + j);
}
parent.setArrayChildren(arrayChildren);
//in this array we add the Parent object. We will use the arrayParents at the setAdapter
arrayParents.add(parent);
}
// set a custom shadow that overlays the main content when the drawer opens
navDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
//set up the drawer's list view with items and click listener
navDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, leftItems));
// HERE I AM navDrawerList.setAdapter(new CustomListAdapter(MainActivity.this, arrayParents));
//navDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// enable ActionBar app icon to behave as action to toggle nav drawer
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
navDrawerToggle=new ActionBarDrawerToggle(this, navDrawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close)
//called when the drawer is completely closed
{
public void onDrawerClosed(View mainView) {
getActionBar().setTitle(navTitle);
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(navDrawerTitle);
invalidateOptionsMenu();
}
};
navDrawerLayout.setDrawerListener(navDrawerToggle);
/*
//swiping controller
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
super.dispatchTouchEvent(event);
return gestureDetector.onTouchEvent(event);
}
SimpleOnGestureListener simpleOnGestureListener = new SimpleOnGestureListener() {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
float sensitvity = 50;
if ((e1.getX() - e2.getX()) > sensitvity) {
SwipeLeft();
} else if ((e2.getX() - e1.getX()) > sensitvity) {
SwipeRight();
}
return true;
}
};
GestureDetector gestureDetector = new GestureDetector(this,
simpleOnGestureListener);
*/
}
/* if(savedInstanceState==null){
selectItem(0);
}*/
#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);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pass the event to ActionBarDrawerToggle, if it returns
// true, then it has handled the app icon touch event
if (navDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle your other action bar items...
return super.onOptionsItemSelected(item);
}
/*private void SwipeLeft() {
navDrawerLayout.closeDrawer(Gravity.RIGHT);
}
private void SwipeRight() {
navDrawerLayout.openDrawer(Gravity.LEFT);
}
*/
}
And here's my ExpandedlistAdapter class.
package com.alpha.omegaRSS;
import java.util.ArrayList;
import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
Import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.TextView;
public class CustomListAdapter extends BaseExpandableListAdapter {
private LayoutInflater inflater;
private ArrayList<Parent> mParent;
public CustomListAdapter(Context context, ArrayList<Parent> parent){
mParent = parent;
inflater = LayoutInflater.from(context);
}
#Override
//counts the number of group/parent items so the list knows how many times calls getGroupView() method
public int getGroupCount() {
return mParent.size();
}
#Override
//counts the number of children items so the list knows how many times calls getChildView() method
public int getChildrenCount(int i) {
return mParent.get(i).getArrayChildren().size();
}
#Override
//gets the title of each parent/group
public Object getGroup(int i) {
return mParent.get(i).getTitle();
}
#Override
//gets the name of each item
public Object getChild(int i, int i1) {
return mParent.get(i).getArrayChildren().get(i1);
}
#Override
public long getGroupId(int i) {
return i;
}
#Override
public long getChildId(int i, int i1) {
return i1;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
//in this method you must set the text to see the parent/group on the list
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
ViewHolder holder = new ViewHolder();
holder.groupPosition = i;
if (view == null) {
view = inflater.inflate(R.id.left_drawer, viewGroup,false);
}
TextView textView = (TextView) view.findViewById(R.layout.list_item_parent);
//"i" is the position of the parent/group in the list
textView.setText(getGroup(i).toString());
view.setTag(holder);
//return the entire view
return view;
}
#Override
//in this method you must set the text to see the children on the list
public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
ViewHolder holder = new ViewHolder();
holder.childPosition = i1;
holder.groupPosition = i;
if (view == null) {
view = inflater.inflate(R.layout.drawer_list_item, viewGroup,false);
}
TextView textView = (TextView) view.findViewById(R.id.child_item);
//"i" is the position of the parent/group in the list and
//"i1" is the position of the child
textView.setText(mParent.get(i).getArrayChildren().get(i1));
view.setTag(holder);
//return the entire view
return view;
}
#Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
/* used to make the notifyDataSetChanged() method work */
super.registerDataSetObserver(observer);
}
/* #Override
public void onClick(View view) {
ViewHolder holder = (ViewHolder)view.getTag();
if (view.getId() == holder.button.getId()){
// DO SOMETHING
}
}*/
protected class ViewHolder {
protected int childPosition;
protected int groupPosition;
protected Button button;
}
}
#Override
//in this method you must set the text to see the parent/group on the list
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
ViewHolder holder = new ViewHolder();
holder.groupPosition = i;
if (view == null) {
// You're inflating a id instead of a layout
// you should inflate your R.layout.[drawer_group_list_item]
view = inflater.inflate(R.id.left_drawer, viewGroup,false);
}
Let me know if this solve it!