For my Android project, I have a listview which has a checkbox for every item. The data is loaded from an SQLite database by using a CursorAdapter class. However, whenever I scroll, the checkbox positions will get moved and get carried down to the next part of the listview. How can I fix this problem?
GIF of my CheckBox Problem
Here's my Cursor Adapter Class:
public class VocabCursorAdapter extends CursorAdapter {
private static final int DIFFICULT = 0;
private static final int FAMILIAR = 1;
private static final int EASY = 2;
private static final int PERFECT = 3;
public VocabCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, 0);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.item_vocab, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvVocabName = (TextView) view.findViewById(R.id.vocabName);
TextView tvVocabDefinition = (TextView) view.findViewById(R.id.vocabDefinition);
ImageView tvVocabLevel = (ImageView) view.findViewById(R.id.vocabLevel);
// Extract properties from cursor
String vocab = cursor.getString(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_VOCAB));
String definition = cursor.getString(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_DEFINITION));
int level = cursor.getInt(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_LEVEL));
// Populate fields with extracted properties
tvVocabName.setText(vocab);
tvVocabDefinition.setText(definition);
if (level == DIFFICULT) {
tvVocabLevel.setImageResource(R.drawable.level_bars_difficult);
tvVocabLevel.setTag(DIFFICULT);
}
else if (level == FAMILIAR) {
tvVocabLevel.setImageResource(R.drawable.level_bars_familiar);
tvVocabLevel.setTag(FAMILIAR);
}
else if (level == EASY) {
tvVocabLevel.setImageResource(R.drawable.level_bars_easy);
tvVocabLevel.setTag(EASY);
}
else if (level == PERFECT) {
tvVocabLevel.setImageResource(R.drawable.level_bars_perfect);
tvVocabLevel.setTag(PERFECT);
}
}
And here's my list item xml, item_vocab.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:longClickable="true">
<ImageView
android:layout_width="36sp"
android:layout_height="36sp"
android:id="#+id/vocabLevel"
android:layout_gravity="right"
android:src="#drawable/level_bars"
android:scaleType="fitXY"
android:contentDescription="#string/vocab_level"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/editCheckbox"
android:layout_toStartOf="#+id/editCheckbox"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/vocabName"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="#+id/vocabLevel"
android:layout_toStartOf="#+id/vocabLevel"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/vocabDefinition"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="#+id/vocabLevel"
android:layout_toStartOf="#+id/vocabLevel"
android:layout_below="#id/vocabName"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/editCheckbox"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
</RelativeLayout>
And here's my xml which contains a listview
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".controller.MyVocab"
android:paddingLeft="5dp">
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/mVocabList"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/empty_text_view"
android:id="#android:id/empty"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
</RelativeLayout>
I have looked at a lot of different solutions on StackOverflow, but I wasn't able to successfully do it in my own app. For an example, this post has a similar problem, but its solution used getView and I had trouble understanding how to implement it with newView and bindView instead.
And some other solutions might be examples where a cursoradapter is not involved. Any help is much appreciated, thanks a lot!
Edit #1: After incorporating Phan's changes, the checkbox states get resets to false rather than keeping its states when I scroll the listview (See ).
Reason : ListView re-uses the views.
Solution :
class VocabCursorAdapter extends CursorAdapter {
List<Integer> selectedItemsPositions;//to store all selected items position
public VocabCursorAdapter(Context context, Cursor c,int flags) {
super(context, c,0);
selectedItemsPositions = new ArrayList<>();
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
View view = LayoutInflater.from(context).inflate(R.layout.item_vocab, viewGroup, false);
CheckBox box = (CheckBox) view.findViewById(R.id.editCheckbox);
box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
int position = (int) compoundButton.getTag();
if (b) {
//check whether its already selected or not
if (!selectedItemsPositions.contains(position))
selectedItemsPositions.add(position);
} else {
//remove position if unchecked checked item
selectedItemsPositions.remove((Object) position);
}
}
});
return view;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
//your other stuff
CheckBox box = (CheckBox) view.findViewById(R.id.editCheckbox);
box.setTag(cursor.getPosition());
if (selectedItemsPositions.contains(cursor.getPosition()))
box.setChecked(true);
else
box.setChecked(false);
}
}
Try this
public class VocabCursorAdapter extends CursorAdapter {
private ArrayList<Boolean> itemChecked = new ArrayList<Boolean>(); // array list for store state of each checkbox
public VocabCursorAdapter(Context context, Cursor c, int flags) {
for (int i = 0; i < c.getCount(); i++) { // c.getCount() return total number of your Cursor
itemChecked.add(i, false); // initializes all items value with false
}
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
...
final int position = cursor.getPosition(); // get position by cursor
CheckBox checkBox = (CheckBox) view.findViewById(R.id.editCheckbox);
checkBox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (itemChecked.get(position) == true) { // if current checkbox is checked, when you click -> change it to false
itemChecked.set(position, false);
} else {
itemChecked.set(position, true);
}
}
});
checkBox.setChecked(itemChecked.get(position)); // set the checkbox state base on arraylist object state
Log.i("In VocabCursorAdapter","position: "+position+" - checkbox state: "+itemChecked.get(position));
}
}
public class ObservationselectattributeFragment extends Fragment {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
Cursor mCsr;
ArrayList<String> attributeItems = new ArrayList<>();
public ObservationselectattributeFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate the layout for this fragment
View view1=inflater.inflate(R.layout.fragment_observationselectattribute, container, false);
//Bundle bundle2 = getArguments();
Bundle bundle1 = getArguments();
final int firsttext= bundle1.getInt("TotalCount");
final String selectedtreatment= bundle1.getString("SelectedTreatment");
Toast.makeText(getActivity(),"value \n"+firsttext+"\n"+"treatment \n"+selectedtreatment, Toast.LENGTH_SHORT).show();
// Toast.makeText(getActivity(),"SelectedTreatment \n"+selectedtreatment, Toast.LENGTH_SHORT).show();
mListView = (ListView)view1.findViewById(R.id.lv001);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
Button addattribute = (Button)view1.findViewById(R.id.addattribute);
addattribute.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String items1="";
Integer tcount1=0;
for(String item1:attributeItems){
items1+="-"+item1+"\n";
tcount1++;
}
Toast.makeText(getActivity(),"you have selected \n"+items1,Toast.LENGTH_LONG).show();
Toast.makeText(getActivity(),"you have selected \n"+tcount1,Toast.LENGTH_LONG).show();
/*FragmentTransaction fr= getFragmentManager().beginTransaction();
fr.replace(R.id.main_container, new ShowObservationDataRecordingFragment()).addToBackStack("ObservationselectattributeFragment");
fr.commit();*/
Bundle bundle = new Bundle();
bundle.putInt("TotalCount2",firsttext);
bundle.putInt("TotalCount1", tcount1);
bundle.putString("SelectedTreatment", selectedtreatment);
Fragment showobservationdatarecordingfragment = new ShowObservationDataRecordingFragment();
showobservationdatarecordingfragment.setArguments(bundle);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.main_container, showobservationdatarecordingfragment).addToBackStack("ObservationselectattributeFragment").commit();
}
});
mDBHandler = new DatabaseHandler(this.getActivity());
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_IDS,
DatabaseHandler.KEY_NAMES,
DatabaseHandler.KEY_FNAME,
DatabaseHandler.KEY_MONAME,
DatabaseHandler.KEY_SNAME
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.euserid,
R.id.eusername,
R.id.efname,
R.id.emoname,
R.id.esname
};
// get and instance of SimpleCursorAdapter
mSCA = new SimpleCursorAdapter(getActivity(),
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// Save the ListView state (= includes scroll position) as a Parceble
Parcelable state = mListView.onSaveInstanceState();
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mListView.setAdapter(mSCA);
// Restore previous state (including selected item index and scroll position)
mListView.onRestoreInstanceState(state);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String attributeItem1 = ((TextView)view.findViewById(R.id.euserid)).getText().toString();
String attributeItem2 = ((TextView)view.findViewById(R.id.eusername)).getText().toString();
String attributeItem3 = ((TextView)view.findViewById(R.id.efname)).getText().toString();
String attributeItem4 = ((TextView)view.findViewById(R.id.emoname)).getText().toString();
String attributeItem5 = ((TextView)view.findViewById(R.id.esname)).getText().toString();
String attributeItem = attributeItem1 + attributeItem2 + attributeItem3 + attributeItem4 + attributeItem5;
// CheckedTextView box = (CheckedTextView) view.findViewById(R.id.record_checkbox);
// box.setChecked(true);
CheckedTextView checkedTextView = (CheckedTextView) view.findViewById(R.id.record_checkbox);
if(checkedTextView.isChecked()) {
checkedTextView.setChecked(false);
} else {
checkedTextView.setChecked(true);
}
if(attributeItems.contains(attributeItem)){
attributeItems.remove(attributeItem);//uncheck item
}
else
{
attributeItems.add(attributeItem);
}
Toast.makeText(getActivity(), "Item1 = " + attributeItem1 +"\n"+ "Item2 ="+attributeItem2 +"\n"+"Item3 ="+attributeItem3+"\n"+"Item4 ="+attributeItem4+"\n"+"Item5 ="+attributeItem5, Toast.LENGTH_SHORT).show();
}
});
((HomeActivity) getActivity())
.setActionBarTitle("Select Attribute");
return view1;
}
}
Related
I'm trying to change the FragmentList item background color after click on this item an confirm an AlertDialog that is shown, it works but it's changing others items beside the clicled item....
This is all my code below...
public class RefrigeranteFragment extends ListFragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public View SelectedView;
String[] refrigerantes = new String[] {
"Coca Cola",
"Coca Cola Zero",
"Fanta Uva",
"Guaraná Antartica",
"Guaraná Antartica Zero",
"Sukita",
"Sukita Laranja",
"Sprite",
"Guaraná Antartica",
"Sukita Uva"
};
// Array of strings to store currencies
String[] precos = new String[]{
"02,50",
"03,00",
"02,00",
"04,50",
"02,50",
"03,45",
"01,50",
"03,90",
"07,00",
"04,50"
};
int[] icones = new int[]{
R.drawable.ic_coca_lata,
R.drawable.ic_coca_zero_lata,
R.drawable.ic_fanta_uva_lata,
R.drawable.ic_guarana_antartica_lata,
R.drawable.ic_guarana_antartica_zero_lata,
R.drawable.ic_sukita_uva_lata,
R.drawable.ic_sukita_laranja_lata,
R.drawable.ic_sprite_lata,
R.drawable.ic_guarana_antartica_pet,
R.drawable.ic_sukita_uva_pet
};
private OnFragmentInteractionListener mListener;
public RefrigeranteFragment() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static RefrigeranteFragment newInstance(String param1, String param2) {
RefrigeranteFragment fragment = new RefrigeranteFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
List<HashMap<String, String>> aList = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < 10; i++){
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("txtNome", refrigerantes[i]);
hm.put("txtPreco", precos[i]);
hm.put("img_refrigerante", Integer.toString(icones[i]));
aList.add(hm);
}
String[] from = {"img_refrigerante", "txtNome", "txtPreco"};
int[] to = {R.id.img_refrigerante, R.id.txtNome, R.id.txtPreco};
SimpleAdapter adapter = new SimpleAdapter(getActivity().getBaseContext(), aList, R.layout.listview_refrigerante_layout, from, to);
setListAdapter(adapter);
// Inflate the layout for this fragment
return super.onCreateView(inflater, container, savedInstanceState);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onListItemClick(ListView listView, View view, int position, long id){
super.onListItemClick(listView, view, position, id);
final View v = view;
final TextView txt = (TextView)view.findViewById(R.id.txtNome);
final ImageView imageView = (ImageView)view.findViewById(R.id.img_refrigerante);
final TextView tvQuantity = (TextView)view.findViewById(R.id.txtQtde);
final TextView lblQuantity = (TextView)view.findViewById(R.id.lblQtde);
final NumberPicker txtQtde = new NumberPicker(getContext());
txtQtde.setMinValue(1);
txtQtde.setMaxValue(10);
if(tvQuantity.getText() != "")
txtQtde.setValue(Integer.parseInt(tvQuantity.getText().toString()));
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(txt.getText());
builder.setMessage("Informe a quantidade");
builder.setIcon(imageView.getDrawable());
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
txtQtde.setLayoutParams(lp);
builder.setView(txtQtde);
builder.setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
tvQuantity.setText(String.valueOf(txtQtde.getValue()));
tvQuantity.setVisibility(View.VISIBLE);
lblQuantity.setVisibility(View.VISIBLE);
v.setBackgroundColor(Color.parseColor("#FF9933"));
((TextView)v.findViewById(R.id.lblNome)).setTextColor(Color.WHITE);
((TextView)v.findViewById(R.id.txtNome)).setTextColor(Color.WHITE);
((TextView)v.findViewById(R.id.lblPreco)).setTextColor(Color.WHITE);
((TextView)v.findViewById(R.id.txtPreco)).setTextColor(Color.WHITE);
((TextView)v.findViewById(R.id.lblQtde)).setTextColor(Color.WHITE);
((TextView)v.findViewById(R.id.txtQtde)).setTextColor(Color.WHITE);
}
});
builder.setNegativeButton("Cancelar",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
}
);
builder.show();
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp">
<ImageView
android:id="#+id/img_refrigerante"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/pizza_fragment"
android:paddingRight="10dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:src="#drawable/ic_menu_pizza2" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_below="#+id/img_refrigerante" >
<TextView
android:id="#+id/lblNome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Refrigerante: "
android:textStyle="bold"
android:textSize="15dp"
android:layout_below="#id/img_pizza" />
<TextView
android:id="#+id/txtNome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15dp"
android:layout_toRightOf="#+id/lblNome" />
<TextView
android:id="#+id/lblPreco"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Preço: "
android:textStyle="bold"
android:textSize="15dp"
android:layout_below="#+id/txtNome" />
<TextView
android:id="#+id/txtPreco"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15dp"
android:layout_toRightOf="#+id/lblPreco"
android:layout_below="#+id/txtNome" />
<TextView
android:id="#+id/lblQtde"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Qtde.: "
android:textStyle="bold"
android:textSize="15dp"
android:visibility="invisible"
android:layout_below="#+id/txtPreco" />
<TextView
android:id="#+id/txtQtde"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15dp"
android:visibility="invisible"
android:layout_toRightOf="#+id/lblQtde"
android:layout_below="#+id/txtPreco" />
</RelativeLayout>
</RelativeLayout>
That is happening because of view recycling within ListView.
In order for this to work, you need three things:
You need variables in your adapter that stores the "clicked" state of the items; for example, a list of booleans.
In your onListItemClick(), you need to call a method on the adapter to change the state of the current item and call notifyDataSetChanged().
In your getView() override, you need to check this state and set the background of the view you are creating accordingly.
Here's code for an adapter (inner class for your activity) that remembers if an item has been clicked (and also the quantity):
public static class MyListAdapter extends BaseAdapter {
private String[] mNames;
private String[] mPrices;
private int[] mIcons;
private int[] mQtys;
private boolean[] mClicked;
public MyListAdapter(String[] names, String[] prices, int[] icons) {
mNames = names;
mPrices = prices;
mIcons = icons;
mQtys = new int[names.length];
mClicked = new boolean[names.length];
}
#Override
public int getCount() {
return mNames.length;
}
#Override
public Object getItem(int position) {
return mNames[position];
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_refrigerante_layout, parent, false);
}
ImageView icon = (ImageView) convertView.findViewById(R.id.img_refrigerante);
icon.setImageResource(mIcons[position]);
TextView name = (TextView) convertView.findViewById(R.id.txtNome);
name.setText(mNames[position]);
TextView price = (TextView) convertView.findViewById(R.id.txtPreco);
price.setText(mPrices[position]);
// hide these if qty == 0
TextView qty = (TextView) convertView.findViewById(R.id.txtQtde);
qty.setText(mQtys[position]);
qty.setVisibility(mQtys[position] == 0 ? View.INVISIBLE : View.VISIBLE);
TextView qtyLbl = (TextView) convertView.findViewById(R.id.lblQtde);
qtyLbl.setVisibility(mQtys[position] == 0 ? View.INVISIBLE : View.VISIBLE);
// here is where we use the clicked flag to determine which colors to set
// TODO put a real color for backgroundColorNormal because I don't know what your normal background color is
int backgroundColor = mClicked[position] ? Color.parseColor("#FF9933") : backgroundColorNormal;
convertView.setBackgroundColor(backgroundColor);
// TODO put a real color for colorNormal because I don't know what your normal text color is
int textColor = mClicked[position] ? Color.WHITE : colorNormal;
((TextView) convertView.findViewById(R.id.lblNome)).setTextColor(textColor);
((TextView) convertView.findViewById(R.id.txtNome)).setTextColor(textColor);
((TextView) convertView.findViewById(R.id.lblPreco)).setTextColor(textColor);
((TextView) convertView.findViewById(R.id.txtPreco)).setTextColor(textColor);
((TextView) convertView.findViewById(R.id.lblQtde)).setTextColor(textColor);
((TextView) convertView.findViewById(R.id.txtQtde)).setTextColor(textColor);
return convertView;
}
public int getQty(int position) {
return mQtys[position];
}
public void setQty(int position, int qty) {
mQtys[position] = qty;
notifyDataSetChanged();
}
public void setClicked(int position, boolean clicked) {
mClicked[position] = clicked;
notifyDataSetChanged();
}
}
When you change a click flag or quantity, notifyDataSetChanged() is called. This is what tells the ListView to ask the adapter again for item views through getView(), and the item views are updated using the new values.
You need to keep a reference to this adapter in your activity:
private MyListAdapter mAdapter;
and set it up:
mAdapter = new MyListAdapter(refrigerantes, precos, icones);
setListAdapter(mAdapter);
then your item click handler would look like this (I simplified it a bit)
#Override
public void onListItemClick(ListView listView, View view, final int position, long id){
super.onListItemClick(listView, view, position, id);
final NumberPicker txtQtde = new NumberPicker(getContext());
txtQtde.setMinValue(1);
txtQtde.setMaxValue(10);
txtQtde.setValue(Integer.parseInt(mAdapter.getQty(position)));
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(refrigerantes[position]);
builder.setMessage("Informe a quantidade");
builder.setIcon(icones[position]);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
txtQtde.setLayoutParams(lp);
builder.setView(txtQtde);
builder.setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
mAdapter.setQty(position, txtQtde.getValue());
mAdapter.setClicked(position);
}
});
builder.setNegativeButton("Cancelar",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
}
);
builder.show();
}
Please -- do more than just copy/paste this and take the time to go through the code line by line to understand how it works. Looking at sample code is a good way to learn about Android, but you won't learn anything if you copy/paste without understanding.
In this link I showed how to change item background color in AlertDialog. It also shows how to customize the AletDialog. For example, how to change divider colro and etc. Please visit this link:
https://stackoverflow.com/a/33439849/5475941.
I hope it helps.
I try to implement a listview multichoice. I achive display all my contact in a listview with checkBox item. My problem is that when check ONLY one item there is lots of element are being cheked. Could you please help?
public class SelectNewGroupChatMembers extends ListFragment implements
LoaderCallbacks<Cursor>, OnItemClickListener {
/** Defines a tag for identifying log entries */
private static final String TAG = "SelectNewGroupChatMembers";
/** The main query adapter */
private ContactsAdapter mAdapter;
/** ListView which will display contacts */
ListView mListView;
/** Fragments require an empty constructor. */
public SelectNewGroupChatMembers() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create the main contacts adapter
mAdapter = new ContactsAdapter(getActivity());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_list, container, false);
mListView = (ListView)view.findViewById(android.R.id.list);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i(TAG, "clicked");
mListView.setAdapter(mAdapter);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
mListView.setOnItemClickListener(this);
// Initialize the loader, and create a loader identified by ContactsQuery.QUERY_ID
getLoaderManager().initLoader(ContactsQuery.QUERY_ID, null, this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle savedInstanceState) {
// If this is the loader for finding contacts in the Content Provider
if (id==ContactsQuery.QUERY_ID) {
Uri contentUri = ContactsQuery.CONTENT_URI;
Log.i(TAG, contentUri.toString());
// Create a new CursorLoader with the following query parameters.
return new CursorLoader(getActivity(),
contentUri,
ContactsQuery.PROJECTION,
ContactsQuery.SELECTION,
null,
ContactsQuery.SORT_ORDER);
}
Log.i(TAG, "onCreateLoader - incorrect ID provided ( "+ id +" )");
return null;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
// This swaps the new cursor into the adapter.
if (loader.getId() == ContactsQuery.QUERY_ID) {
Log.i(TAG,cursor.toString());
// The asynchronous load is complete and the data
// is now available for use. Only now can we associate
// the queried Cursor with the SimpleCursorAdapter.
mAdapter.swapCursor(cursor);
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
if (loader.getId() == ContactsQuery.QUERY_ID) {
// When the loader is being reset, clear the cursor from the adapter.
// This allows the cursor resources to be freed.
mAdapter.swapCursor(null);
}
}
private class ContactsAdapter extends CursorAdapter {
private LayoutInflater mInflater;
public ContactsAdapter(Context context) {
super(context, null, 0);
// Stores the inflater for the later use
mInflater = LayoutInflater.from(context);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
// Inflate the list item layout
final View itemLayout =
mInflater.inflate(R.layout.fragment_select_new_group_chat_members, viewGroup, false);
// Use ViewHolder design pattern to store each view resource.
// This allows bindView() to retrieve stored references instead of
// calling findViewById for each instance of the layout.
final ViewHolder holder = new ViewHolder();
holder.contactName = (TextView)itemLayout.findViewById(R.id.userName);
holder.contactNo = (TextView)itemLayout.findViewById(R.id.userInfo);
// Store the resourceHolder instance in Layout.
// This makes resourceHolder available to bindView
// and other methods that receive a handle to the item view
itemLayout.setTag(holder);
return itemLayout;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Get handles to individual view sources
final ViewHolder holder = (ViewHolder) view.getTag();
final String contactName = cursor.getString(ContactsQuery.DISPLAY_NAME);
final String contactNumber = cursor.getString(ContactsQuery.PHONE_NUMBER);
holder.contactName.setText(contactName);
holder.contactNo.setText(contactNumber);
}
private class ViewHolder {
public TextView contactName, contactNo;
}
}
public interface ContactsQuery {
// This query ID will be used in Loader
final static int QUERY_ID = 1;
// A content URI for the Contacts table
final static Uri CONTENT_URI = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
final static String SELECTION = null;
final static String SORT_ORDER = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME;
final static String [] PROJECTION = {
ContactsContract.CommonDataKinds.Phone._ID,
ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
SORT_ORDER,
};
final static int ID = 0;
final static int LOOKUP_KEY = 1;
final static int DISPLAY_NAME = 2;
final static int PHONE_NUMBER = 3;
final static int SORT_KEY = 4;
}
}
My layout file is as below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="6dip" >
<ImageView
android:id="#+id/userImage"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="6dip"
android:src="#drawable/ic_action_user" />
<CheckBox
android:id="#+id/checkBox"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignBottom="#id/userImage"
android:layout_alignTop="#id/userImage"
android:layout_alignParentRight="true"
android:focusable="false"
android:gravity="center" />
<TextView
android:id="#+id/userName"
android:layout_alignTop="#id/userImage"
android:layout_toRightOf="#id/userImage"
android:layout_toLeftOf="#id/checkBox"
android:layout_width="wrap_content"
android:layout_height="25dp"
android:gravity="center_vertical"
android:text="ContactName"
android:textStyle="bold" />
<TextView
android:id="#+id/userInfo"
android:layout_alignBottom="#id/userImage"
android:layout_toRightOf="#id/userImage"
android:layout_toLeftOf="#id/checkBox"
android:layout_width="wrap_content"
android:layout_height="25dp"
android:gravity="center_vertical"
android:text="UserInfo" />
</RelativeLayout>
At final my code is like above. This code queries contacts and display them on a listview which including a checkBox. I tried some different code snippets but with all my tries i get same result. My problem is that when check ONLY one item there is lots of element are being cheked. Could you help please?
I don't see where you are manipulating the checkbox on item click in this code. Ideally onItemClick you should get the Holder object out of the view tag by calling view.getTag. In your holder there is a checkbox view instance so you can enable the checkbox there. So something like this on your onItemClick method.
Holder holder = (Holder) view.getTag();
holder.checkbox.setChecked(!checkbox.isChecked());
So I'm trying to make a custom SimpleCursorAdapter, because I want to make list rows that look something like this:
ToggleButton | TextView | ImageButton,
and I know of no way to do this without making a custom adapter.
The problem being that my code doesn't work and I'm not really sure why. Even if there's no data to be displayed, I get a row with the default format:
ToggleButton | "default" | ImageButton.
Furthermore, all rows displayed look exactly the same as the default row, and the OnClickListener I set up doesn't do anything.
Can someone tell me what I'm doing wrong, or at least point me in the direction of a decent tutorial for how to deal with custom CursorAdapters and OnClickListeners? Because I've been totally unable to find anything remotely helpful.
Here is my code for the adapter:
public class AlarmCursorAdapter extends SimpleCursorAdapter {
private Cursor mCursor;
private Context mContext;
private Activity mActivity;
public AlarmCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
// TODO Auto-generated constructor stub
mCursor = c;
mContext = context;
mActivity = (Activity) context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(view == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.alarm_list_row, parent, false);
}
if(mCursor == null || mCursor.getCount() == 0) {
return view;
}
mCursor.moveToPosition(position);
// Set the alarm time view
TextView alarmView = (TextView) view.findViewById(R.id.alarmView);
int timeStringIndex = mCursor.getColumnIndexOrThrow(DailyAlarmTable.ALARM_TIME);
String alarmTime = mCursor.getString(timeStringIndex);
alarmView.setText(alarmTime);
// Set up the toggle button
int isActiveIndex = mCursor.getColumnIndexOrThrow(DailyAlarmTable.ALARM_ISACTIVE);
int isActive = mCursor.getInt(isActiveIndex);
ToggleButton alarmToggle = (ToggleButton)view.findViewById(R.id.alarmToggle);
if(isActive == 1) {
alarmToggle.setChecked(true);
} else {
alarmToggle.setChecked(false);
}
final int currentPosition = mCursor.getPosition();
int idIndex = mCursor.getColumnIndexOrThrow(DailyAlarmTable.ALARM_ID);
final long alarmId = mCursor.getLong(idIndex);
alarmToggle.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
String toastStr = "clicked alarm " + alarmId + " at position " + currentPosition;
Toast.makeText(mContext, toastStr, Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
Here's the implementation, which occurs inside a fragment:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
/*
mAdapter = new SimpleCursorAdapter(getActivity(),
R.layout.alarm_list_row, null,
new String[] { DailyAlarmTable.ALARM_TIME, DailyAlarmTable.ALARM_ISACTIVE },
new int[] { R.id.alarmView, R.id.alarmToggle }, 0);
*/
mAdapter = new AlarmCursorAdapter(getActivity(),
R.layout.alarm_list_row, null,
new String[] { DailyAlarmTable.ALARM_TIME, DailyAlarmTable.ALARM_ISACTIVE },
new int[] { R.id.alarmView, R.id.alarmToggle }, 0);
//mAdapter.setViewBinder(new AlarmViewBinder());
ListView alarmList = (ListView) this.getActivity().findViewById(R.id.alarmListView);
TextView emptyView = (TextView) this.getActivity().findViewById(R.id.empty);
alarmList.setEmptyView(emptyView);
alarmList.setAdapter(mAdapter);
// Initialize the loader
getLoaderManager().initLoader(1, savedInstanceState, this);
}
Here's the XML file for the row:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ToggleButton
android:id="#+id/alarmToggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="#string/details_default" />
<TextView
android:id="#+id/alarmView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/details_default"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ImageButton
android:id="#+id/alarmDiscard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_discard"
android:contentDescription="#string/alarm_discard_description" />
</LinearLayout>
If there's any other code you need, I can gladly add that. Thank you very much in advance.
As suggested by pskink's comment, the solution was not to use a custom SCA at all, but to just implement a View Binder.
I have ONE annoying problem with SimpleCursorAdapter. My programm has list view and ListActivity. Each row has it's own layout:
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content" android:layout_width="fill_parent"
android:orientation="horizontal" android:weightSum="1.0">
<TableRow>
<TextView android:id="#+id/task_time"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="24sp" android:text="Time">
</TextView>
<LinearLayout android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="fill_parent">
<TextView android:id="#+id/task_name"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="20sp" android:text="Name">
</TextView>
<TextView android:id="#+id/task_categoty"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Category" android:textSize="12sp">
</TextView>
</LinearLayout>
<TextView android:id="#+id/task_state"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="State" android:textSize="12sp">
</TextView>
<CheckBox android:id="#+id/task_enabled"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:focusable="false">
</CheckBox>
</TableRow>
Tasks are stored in SQLite database. I have DAO object (singleton) to access the database.
TaskDao:
public void updateEnabled(int id, boolean enabled){
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(ENABLED_COLUMN, enabled==true?1:0);
Log.i(TAG, "update to " + cv.get(ENABLED_COLUMN) );
try{
db.beginTransaction();
db.update(TASK_TABLE, cv, ID_COLUMN+"=?", new String[]{id+""});
db.setTransactionSuccessful();
} catch (SQLException e) {
Log.i(TAG, "edit task failed!");
} finally {
db.endTransaction();
if (db != null)
db.close();
}
}
and the Cursor method for ListActivity:
public Cursor getTasks(){
SQLiteDatabase db = dbHelper.getReadableDatabase();
return db.query(TASK_TABLE, COLUMNS, null, null, null, null, NAME_COLUMN);
}
I extended SimpleCursorAdapter (TaskDbAdapter) like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
convertView = inflater.inflate(R.layout.task_list_row, null);
}
Cursor c = getCursor();
c.moveToPosition(position);
Log.i(TAG, "getView " + position + " = " + c.getInt(enabledIdx));
enabled.setTag(c.getInt(c.getColumnIndex(BaseColumns._ID)));
enabled.setChecked(c.getInt(enabledIdx)>0?true:false);
enabled.setOnClickListener(this);
return convertView;
}
#Override
public void onClick(View v) {
CheckBox box = (CheckBox) v;
Integer id = (Integer)box.getTag();
TaskDao.getInstance(context).updateEnabled(id.intValue(), box.isChecked());
}
And at last I use all the above stuff in my main ListActivity
private void refreshList(){
c = TaskDao.getInstance(this).getTasks();
startManagingCursor(c);
adapter = new TaskDbAdapter(this, R.layout.task_list_row, c, new String[]{TaskDao.ENABLED_COLUMN}, new int[]{R.id.task_enabled});
setListAdapter(adapter);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.task);
getListView().setItemsCanFocus(false);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
getListView().setVerticalScrollBarEnabled(true);
registerForContextMenu(getListView());
getListView().setOnCreateContextMenuListener(this);
refreshList();
}
#Override
protected void onResume() {
super.onResume();
refreshList();
}
#Override
protected void onPause() {
super.onPause();
}
Everything works fine. But CheckBoxes loose their states. For instance I check my first column and scroll the list down. In my trace before press I have:
getView 0 = 0
getView 2 = 0
getView 3 = 0
then
uptate to 1
and then (when I scroll up to the first element)
getView 0 = 0
getView 2 = 0
getView 3 = 0
I tried to make getCursor().requery(); in my TaskDbAdapter onClick method. But then I saw no items in the list! And exception because of cursor management(connection was closed by android). When I write startManagingCursor(c); in refreshList() method then check and uncheck methods don't work.
Please, Help!
I didn't read all your source so my suggestion may be totally wrong, but I will give a try.
Take a look at the documentation of BaseAdapter class.
public void notifyDataSetChanged ()
may do the work.
You also can register Observer for this...
public void registerDataSetObserver (DataSetObserver observer)
I struggled with this as well. I ended up storing all checked boxes in the db as either 0 or 1. Then I check their state from the database to determine if they are marked or not.
public class DetailCursorAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
public DetailCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
this.c = c;
this.context = context;
}
public View getView(int pos, View inView, ViewGroup parent) {
View v = inView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.check_list, null);
}
Log.i("pos = ..................", "pos = "+pos);
this.c.moveToPosition(pos);
//this.c.moveToPosition(this.c.getInt(this.c.getColumnIndex("_id")));
CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck);
cBox.setTag(this.c.getInt(this.c.getColumnIndex("_id")));
/*
* when reloading the list, check for chkd status, this is broken. Need to query db directly.
*/
EventDbAdapter mDbHelper = new EventDbAdapter(context);
mDbHelper.open();
int idTag = (Integer) cBox.getTag();
int checked = mDbHelper.selectChk(idTag);
mDbHelper.close();
Log.i("results from selectChk.....................", ""+checked);
if (checked == 1) {
cBox.setChecked(true);
} else {
cBox.setChecked(false);
}
/*
* Populate the list
*/
TextView txtdateTime = (TextView)v.findViewById(R.id.time);
txtdateTime.setText(this.c.getString(this.c.getColumnIndex("time")));
TextView txtdateEvent = (TextView)v.findViewById(R.id.event);
txtdateEvent.setText(this.c.getString(this.c.getColumnIndex("event")));
TextView txtdateLocation = (TextView)v.findViewById(R.id.location);
txtdateLocation.setText(this.c.getString(this.c.getColumnIndex("location")));
ImageView arrow = (ImageView) v.findViewById(R.id.arrowId);
arrow.setImageResource(R.drawable.rightarrow);
Log.i("if chk in db is = 1 then set checked.........",this.c.getString(this.c.getColumnIndex("checked")) +" " +this.c.getString(this.c.getColumnIndex("time")));
/*
* Controls action based on clicked list item (background)
*/
View lv = v.getRootView();
lv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View lv) {
CheckBox cBox = (CheckBox) lv.findViewById(R.id.bcheck);
// id holds the rowid of each event. pass this to a new activity to query for description
// Call Event Detail
String id = cBox.getTag().toString();
Intent i = new Intent(context, EventDetail.class);
//i.putExtra("description", c.getString(c.getColumnIndex("description")));
i.putExtra("_id", id);
context.startActivity(i);
}
});
/*
* Begin - Controls action based on clicked Text only
txtdateEvent.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
CharSequence charseq = "Darth Vader is alive";
Toast.makeText(context, charseq, Toast.LENGTH_SHORT).show();
}
});
* End - Controls action based on clicked Text only
*/
/*
* Controls action based on clicked checkbox
*/
cBox.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
EventDbAdapter mDbHelper = new EventDbAdapter(context);
mDbHelper.open();
CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck);
if (cBox.isChecked()) {
//cBox.setChecked(false);
CharSequence charseq = "Added to My Schedule";
Toast.makeText(context, charseq, Toast.LENGTH_SHORT).show();
// Update the database for each checked item
mDbHelper.updateChecked(cBox.getTag().toString(), "1");
c.requery();
// Verify that the db was updated for debugging purposes
String event = c.getString(c.getColumnIndex("event"));
int id = (Integer) cBox.getTag();
Log.i("checked _id...........", "id= " + id + " " +c.getString(c.getColumnIndex("_id")));
Log.i("checked checked...........", ""+c.getString(c.getColumnIndex("checked")));
} else if (!cBox.isChecked()) {
//cBox.setChecked(true);
CharSequence charseq = "Removed from My Schedule";
Toast.makeText(context, charseq, Toast.LENGTH_SHORT).show();
// checkList.remove(cBox.getTag());
//checkList.add((Integer) cBox.getTag());
String event = c.getString(c.getColumnIndex("event"));
//int id = c.getInt(c.getColumnIndex("_id"));
int id = (Integer) cBox.getTag();
mDbHelper.updateChecked(cBox.getTag().toString(), "0");
c.requery();
//int sqlresult = mDbHelper.selectChk(id, event);
//Log.i("sqlresult checked value after update...........", ""+ sqlresult);
//Log.i("unchecked _id...........", ""+c.getString(c.getColumnIndex("_id")));
//Log.i("unchecked checked...........", ""+c.getString(c.getColumnIndex("checked")));
}
//mDbHelper.close();
}
});
return(v);
}
}
What i am trying to do is catch a Button click that is inside a ListView managed by a CustomCursorAdapter. when clicked i need to make the button invisible and update a value in the database. here is the code i am using for the ListActivity and the CursorAdapter.
public class MainTabView extends ListActivity{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
fillListData();
}
private void fillListData(){
DataBaseNamesHelper myDbNamesHelper = new DataBaseNamesHelper(this);
myDbNamesHelper.openDataBase();
Cursor cursor = myDbNamesHelper.getCursorQueryWithAllTheTaxiStations();
startManagingCursor(cursor);
// the desired columns to be bound
String[] columns = new String[] { DataBaseNamesHelper.COLUMN_NAME, DataBaseNamesHelper.COLUMN_PEOPLE};
// the XML defined views which the data will be bound to
int[] to = new int[] { R.id.name_entry, R.id.number_entry };
// create the adapter using the cursor pointing to the desired data as well as the layout information
CustomCursorAdapter mAdapter = new CustomCursorAdapter(this, R.layout.list_entry, cursor, columns, to);
// set this adapter as your ListActivity's adapter
this.setListAdapter(mAdapter);
this.getListView().setOnItemClickListener(mAdapter);
myDbNamesHelper.close();
}
and the Adapter:
public class CustomCursorAdapter extends SimpleCursorAdapter implements SectionIndexer,Filterable,
android.widget.AdapterView.OnItemClickListener{
private Context context;
private int layout;
private AlphabetIndexer alphaIndexer;
public CustomCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.context = context;
this.layout = layout;
alphaIndexer=new AlphabetIndexer(c, c.getColumnIndex(DataBaseNamesHelper.COLUMN_NAME), " ABCDEFGHIJKLMNOPQRSTUVWXYZ");
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
Cursor c = getCursor();
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
int nameCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_NAME);
String name = c.getString(nameCol);
/**
* Next set the name of the entry.
*/
TextView name_text = (TextView) v.findViewById(R.id.name_entry);
if (name_text != null) {
name_text.setText(name);
}
int favCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_FAVOURITED);
int fav = c.getInt(favCol);
Button button = (Button) v.findViewById(R.id.Button01);
if(fav==1){
button.setVisibility(View.INVISIBLE);
}
return v;
}
#Override
public void bindView(View v, Context context, Cursor c) {
int nameCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_NAME);
String name = c.getString(nameCol);
/**
* Next set the name of the entry.
*/
TextView name_text = (TextView) v.findViewById(R.id.name_entry);
if (name_text != null) {
name_text.setText(name);
}
int favCol = c.getColumnIndex(DataBaseNamesHelper.COLUMN_FAVOURITED);
int fav = c.getInt(favCol);
Button button = (Button) v.findViewById(R.id.Button01);
Log.e("fav",String.valueOf(fav));
if(fav==1){
button.setVisibility(View.INVISIBLE);
}
}
#Override
public int getPositionForSection(int section) {
return alphaIndexer.getPositionForSection(section);
}
#Override
public int getSectionForPosition(int position) {
return alphaIndexer.getSectionForPosition(position);
}
#Override
public Object[] getSections() {
return alphaIndexer.getSections();
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Log.e("item Click", arg1.toString()+ " position> " +arg2);
}
i have already set the button to be clickable(true) and focusable(false).
with this code i can achieve what i want but by clicking the listView row (logs only item clicks on the LinearLayout that is holding the button. how do i make the button receive click exactly the same as LinearLayout does?
here is the row layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:orientation="horizontal" android:focusable="false">
<TextView
android:id="#+id/name_entry"
android:layout_height="wrap_content"
android:textSize="28dip" android:layout_width="wrap_content" android:layout_weight="1" android:layout_gravity="center_vertical"/>
<Button android:id="#+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Fav" android:layout_gravity="center_vertical" android:layout_marginRight="10dp" android:focusable="false" android:clickable="true"></Button><TextView
android:id="#+id/number_entry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="28dip" />
</LinearLayout>
you need a new aproach as is this described in the button documentation.
However, instead of applying an OnClickListener to the button in your activity, you can assign a method to your button in the XML layout, using the android:onClick attribute. For example:
<Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="#string/self_destruct"
android:onClick="selfDestruct" />
Now, when a user clicks the button, the Android system calls the activity's selfDestruct(View) method. In order for this to work, the method must be public and accept a View as its only parameter. For example:
public void selfDestruct(View view) {
// Kabloey
}
The View passed into the method is a reference to the widget that was clicked. You can setTag() on the View in the adapter to recognize which button was clicked.
Try adding the following line in your item layout xml file. This should be added to the root layout.
<LinearLayout .....
android:descendantFocusability="beforeDescendants"
..... />
From there you can set your onClickListener of the button in the getView method of your adapter.