Activity class code:
conversationList = (ListView)findViewById(android.R.id.list);
ConversationArrayAdapter conversationArrayAdapter=new ConversationArrayAdapter(this, R.layout.conversation_list_item_format_left, conversationDetails);
conversationList.setAdapter(conversationArrayAdapter);
conversationList.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
Log.d("test","clicked");
}
});
The getView function in the Adapter class:
if (v == null) {
LayoutInflater vi = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(leftSideMessageNumber.equals(m.getTo())) {
v = vi.inflate(R.layout.conversation_list_item_format_left, null);
} else {
v = vi.inflate(R.layout.conversation_list_item_format_right, null);
}
}
Is there a problem with using two xmls while inflating?
I just found a solution from here, but by deep clicking.
If any row item of list contains focusable or clickable view then OnItemClickListener won't work.
The row item must have a param like
android:descendantFocusability = "blocksDescendants".
Here you can see an example of how your list item should look like.
Your list item xml should be...
row_item.xml (your_xml_file.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:descendantFocusability="blocksDescendants"
android:gravity="center_vertical" >
// your other widgets here
</LinearLayout>
The problem is that your layouts contain either focusable or clickable items.
If a view contains either focusable or clickable item the OnItemCLickListener won't be called.
Click here for more information.
Please post one of your layout xmls if that isn't the case.
For my lists, my rows have other things that can be clicked, like buttons, so doing a blanket blocksDescendants doesn't work. Instead I add a line in the button's xml:
android:focusable="false"
That keeps the buttons from blocking the clicks on the rows, but still lets the buttons take the clicks, too.
you need to do 2 steps in your listview_item.xml
set the root layout with: android:descendantFocusability="blocksDescendants"
set any focusable or clickable view in this item with:
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
Here is an example: listview_item.xml
<?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:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:gravity="center_vertical"
android:orientation="vertical"
android:descendantFocusability="blocksDescendants">
<RadioButton
android:id="#+id/script_name_radio_btn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textColor="#000"
android:padding="5dp"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
/>
</LinearLayout>
use the below code inside button tag in custom row layout of listview
android:focusable="false"
android:clickable="false"
I had the same problem and I just saw I had accidentally set:
#Override
public boolean isEnabled(int position)
{
return false;
}
on my CustomListViewAdapter class.
By changing this to:
return true;
I've managed to fix the problem.
Just in case if someone has done the same mistake...
Use android:descendantFocusability
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dip"
android:background="#color/light_green"
android:descendantFocusability="blocksDescendants" >
Add above in root layout
I solved it with the help of this answer
1.Add the following in Linear Layout of list_items.xml
android:descendantFocusability="blocksDescendants"
2.Child Views of LinearLayout in list_items.xml
android:focusable="false"
if you have textviews, buttons or stg clickable or selectable in your row view only
android:descendantFocusability="blocksDescendants"
is not enough. You have to set
android:textIsSelectable="false"
to your textviews and
android:focusable="false"
to your buttons and other focusable items.
Even I was having the same problem, I am having checkbox, did the following to masker itemClickListener work,
Added the following properties to the checkbox,
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
and ItemClickListner started working.
For detailed example you can go through the link,
http://knowledge-cess.com/android-itemclicklistner-with-checkbox-or-radiobutton/
Hope it helps Cheers!!
I had the same problem and tried all of the mentioned solutions to no avail. through testing i found that making the text selectable was preventing the listener to be called. So by switching it to false, or removing it my listener was called again.
android:textIsSelectable="false"
hope this helps someone who was stuck like me.
Add this in main Layout
android:descendantFocusability="blocksDescendants"
Write this code into every button,Textview,ImageView etc which have
onClick
android:focusable="false"
android:clickable="false"
Hope it will work.
Two awesome solutions were this, if your extending ListFragment from a fragment, know that mListView.setOnItemClickListener wont be called before your activity is created, this ensured it is set when activity has been created
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) {
// Do the onItemClick action
Log.d("ROWSELECT", "" + rowId);
}
});
}
While looking at the source code for ListFragment, I came across this
public class ListFragment extends Fragment {
...........................................
................................................
final private AdapterView.OnItemClickListener mOnClickListener
= new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
onListItemClick((ListView)parent, v, position, id);
}
};
................................................................
................................................................
public void onListItemClick(ListView l, View v, int position, long id) {
}
}
An onItemClickListener object is attached and it calls onListItemClick()
As such the other similar solution, which works in the exact same way is to override onListItemClick()
#Override
public void onListItemClick(ListView l, View v, int position, long rowId) {
super.onListItemClick(l, v, position, id);
// Do the onItemClick action
Log.d("ROWSELECT", "" + rowId);
}
in my case none of xml layout properties was not helpful.
I just add a single line of code like this:
convertView.setClickable(false);
#NonNull
#Override
public View getView(final int position, View convertView, #NonNull ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null || convertView.getTag() == null) {
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.my_layout_id, parent, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
...
convertView.setClickable(false);
return convertView;
}
so basically it do the same thing as setting up properties in xml layout but it was only thing which works in my case.
It is not perfect timing but maybe it will helps somebody
Happy coding
I've tried all the above and NOTHING worked.
I solved the problem as follows:
First I define a custom Button called ListButton
public class ListButton extends android.widget.Button
{
private ButtonClickedListener clickListener;
public ListButton(Context context)
{
this(context, null);
}
public ListButton(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public ListButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
public void setClickListener(ButtonClickedListener listener) {
this.clickListener = listener;
}
#Override
public boolean isInTouchMode() {
return true;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return false;
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
eventClicked();
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_MOVE:
break;
default :
}
return true;
}
private void eventClicked() {
if (this.clickListener!=null) {
this.clickListener.ButtonClicked();
}
}
}
The XML looks like:
<dk.example.views.ListButton
android:id="#+id/cancel_button"
android:layout_width="125dp"
android:layout_height="80dp"
android:text="Cancel"
android:textSize="20sp"
android:layout_margin="10dp"
android:padding="2dp"
android:background="#000000"
android:textColor="#ffffff"
android:textStyle="bold"
/>
Then I define my own ButtonClicked Listener interface:
public interface ButtonClickedListener {
public void ButtonClicked();
}
Then I use my own listener just as if it was the normal OnClickListener:
final ListButton cancelButton = (ListButton) viewLayout.findViewById(R.id.cancel_button);
cancelButton.setClickListener(new ButtonClickedListener() {
#Override
public void ButtonClicked() {
//Do your own stuff here...
}
});
I had the same issue, I was using a style for my texts in the row layout that had the "focusable" attribute. It worked after I removed it.
In my case, I had to remove the next line from the Layout
android:clickable="true"
Android:autoText attribute also makes TextView auto focusable.
If you want to use both the simple click and long click on list view items better way to implement that would be to use context menu for long click. Avoid using setItemLongClickListener especially if you have multiple row layouts for your listview.
Faced same problem, tried for hours. If you have tried all of the above than try changing layout_width of Listview and list item to match_parent from wrap_content.
All of the above failed for me. However, I was able to resolve the problem (after many hours of banging my head - Google, if you're listening, please consider fixing what I encountered below in the form of compiler errors, if possible)
You really have to be careful of what android attributes you add to your xml layout here (in this original question, it is called list_items.xml). For me, what was causing the problem was that I had switched from an EditText view to a TextView and had leftover attribute cruft from the change (in my case, inputType). The compiler didn't catch it and the clickability just failed when I went to run the app. Double check all of the attributes you have in your layout xml nodes.
private AdapterView.OnItemClickListener onItemClickListener;
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
.......
final View view = convertView;
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(null, view, position, -1);
}
}
});
return convertView;
}
public void setOnItemClickListener(AdapterView.OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
Then in your activity, use adapter.setOnItemClickListener() before attaching it to the listview.
Copied from github its worked for me
The thing that worked for me was to add the below code to every subview inside the layout of my row.xml file:
android:focusable="false"
android:focusableInTouchMode="false"
So in my case:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:focusable="false"
android:focusableInTouchMode="false"
android:id="#+id/testingId"
android:text="Name"
//other stuff
/>
<TextView
android:focusable="false"
android:focusableInTouchMode="false"
android:id="#+id/dummyId"
android:text="icon"
//other stuff
/>
<TextView
android:focusable="false"
android:focusableInTouchMode="false"
android:id="#+id/assignmentColor"
//other stuff
/>
<TextView
android:focusable="false"
android:focusableInTouchMode="false"
android:id="#+id/testID"
//other stuff
/>
<TextView
android:focusable="false"
android:focusableInTouchMode="false"
android:text="TextView"
//other stuff
/>
</android.support.constraint.ConstraintLayout>
And this is my setOnItemClickListener call in my Fragment subclass:
CustomListView = (PullToRefreshListCustomView) layout.findViewById(getListResourceID());
CustomListView.setAdapter(customAdapter);
CustomListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d("Testing", "onitem click working");
// other code
}
});
I got the answer from here!
Had the same problem with onClick. The solution was to remove from the xml the following
android:tooltipText=""
I solved the problem by removing the clickable views from the list.
Related
let's say that i have a list of items and i want to build a form with each of these items. This form consist of two checkboxes and an editText. For example i want to know if each item is present in a warehouse and its quantity. I'm thinking for solving my problem to use a listview where each element of my listview will consist of the name of an item, two checkboxes and an editText.
The problem is that the only use of listview i know to present list of elements, i don't how to solve my problem with it (i'm a beginner in android). Can someone help me ?
Is there another way to solve my problem ? Thank you
Try to implements a cusom ListView adapter! This is easier than you might think!
First you need to create layout which would will represent each item in your list:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test TEST" />
<LinearLayout android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignBottom="#id/itemTextView"
android:layout_alignParentRight="true">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/doneCheckBox" />
</LinearLayout>
Then implement cusom adapter inside your code:
public CusomAdapter(Context mainContex, YourItems<SomeItem> someItems) {
this.mainContex = mainContex;
this.someItems = someItems;
}
#Override
public int getCount() {
return someItems.size();
}
#Override
public Object getItem(int position) {
return someItems.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View item = convertView;
if (item == null) {
item = LayoutInflater.from(mainContex).inflate(R.layout.shoplist_item, null); // your listView layout here!
}
//fill listView item with your data here!
//initiate your check box
CheckBox doneCheckBox = (CheckBox)item.findViewById(R.id.doneCheckBox);
//add a checkbox listener
doneCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
doneCheckBox.ischecked=true;
}
else{
doneCheckBox.ischecked=false;
}
}
});
return item;
}
don't forget to add ListView element inside your Activity layout!
I have used a custom adapter for populating my Spinner. I have overriden getDropDownView from which I return the view of each row of the dropdown list. Everything works fine except the dropdown list rendered is not getting the width of the Spinner widget. Rather it gets Like this:
So the dropdown list is missing the highlighted width. I dont know why this is happening. I want it to get the full width of the spinner.
My custom adapter:
class CategorySpinnerAdapter extends ArrayAdapter{
private Activity context;
ArrayList<Category> categoryList;
public CategorySpinnerAdapter(Activity context,int resourceID,ArrayList<Category> categoryList)
{
super(context,resourceID,categoryList);
this.context=context;
this.categoryList=categoryList;
}
#Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
// TODO Auto-generated method stub
if(convertView==null)
{
LayoutInflater inflater=context.getLayoutInflater();
convertView=inflater.inflate(R.layout.category_spinner_row, parent,false);
}
Category currentCategory=categoryList.get(position);
TextView categoryText=(TextView) convertView.findViewById(R.id.spinnerText);
categoryText.setText(currentCategory.getCategoryName());
return convertView;
}
}
Code, where I am setting this adapter:
Spinner categorySpinner=(Spinner) getActivity().findViewById(R.id.categorySpinner);
ArrayList<Category> categoryList=populateCategoryList();
CategorySpinnerAdapter categorySpinnerAdapter=new CategorySpinnerAdapter(getActivity(), android.R.layout.simple_spinner_item,categoryList);
categorySpinner.setAdapter(categorySpinnerAdapter);
categorySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView,
int position, long id) {
// TODO Auto-generated method stub
ArrayList<Reward> modifiedList=new ArrayList<Reward>();
//test case: category OK
int categoryID=position+1;
for(int i=0;i<rewardList.size();i++)
{
if(rewardList.get(i).getCategoryID()==categoryID)
{
modifiedList.add(rewardList.get(i));
}
}
adapter.changeDataSet(modifiedList);
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
//get default ELECTRONICS category 1 data to populate the list
ArrayList<Reward> defaultCategorizedList=new ArrayList<Reward>();
//test case: category OK
for(int i=0;i<rewardList.size();i++)
{
if(rewardList.get(i).getCategoryID()==1)
{
defaultCategorizedList.add(rewardList.get(i));
}
}
}
});
Declaration of the Spinner Item inside the main xml:
<Spinner
android:id="#+id/categorySpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/customerRewardPointsTextView"
android:background="#drawable/btn_dropdown"
android:spinnerMode="dropdown" />
layout for the dropdown items, category_spinner_row.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/category_spinner_background" >
<TextView
android:id="#+id/spinnerText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:ellipsize="marquee"
android:gravity="center"
android:singleLine="true" />
</RelativeLayout>
How can I fix this issue ?
try this one:
convertView=inflater.inflate(android.R.layout.simple_list_item_1, parent,false);
The problem starts because of "android:background="#drawable/btn_dropdown"" this portion of code. When you remove this you will see the spinner is working as it is supposed to, that means btn_dropdown drawable is conflicting with your spinner's width and eventually it's popup window that's why you are seeing this weird behaviour. I would suggest you to adjust your btn_dropdown drawable so that it does not conflict with spinner's default behaviour. Take a look at these post:
how-to-design-spinner-in-android
change-spinner-background
I haven't tried those but i think you will find what you need.
I am working on an app where the list item are complex, TextView and two ImageButtons. I have looked at the around for a solution, and tried all that I have seen, still nothing.
The list is part of the ListFragment on I have Override onListItemClick.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFF" >
<TextView
android:id="#+id/medcine_info_txt"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:padding="3dp"
android:textColor="#color/black" />
<ImageButton
android:id="#+id/item_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/medcine_info_txt"
android:layout_alignParentLeft="true"
android:contentDescription="#string/item_edit"
android:focusable="false"
android:focusableInTouchMode="false"
android:src="#android:drawable/ic_menu_edit" />
<ImageButton
android:id="#+id/item_history"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/medcine_info_txt"
android:layout_centerHorizontal="true"
android:contentDescription="#string/item_history"
android:focusable="false"
android:focusableInTouchMode="false"
android:src="#android:drawable/btn_star" />
</RelativeLayout>
This my adapter getView where I have on handle the buttons click, and it implements OnClickListener
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflator = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View listItem = inflator.inflate(R.layout.medcince_list_item, null);
ImageButton mEdit = (ImageButton)listItem.findViewById(R.id.item_edit);
mEdit.setOnClickListener(this);
mEdit.setTag(getItem(position));
ImageButton mHistory = (ImageButton)listItem.findViewById(R.id.item_history);
mHistory.setOnClickListener(this);
mHistory.setTag(getItem(position));
return listItem;
}
Any thoughts on why the onListItemClick is not handling the click?
I think your ImageButton is stealing away the onItemClickLister event. Add this attribute to your layout
android:descendantFocusability="blocksDescendants"
<TextView
android:id="#+id/medcine_info_txt"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:padding="3dp"
android:textColor="#color/black" />
<ImageButton
android:id="#+id/item_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
.......
Thanks
This is common question for ListView. I read source code about this.
Question: why onListItemClick not be called?
Answer:
AbsListView class override onTouchEvent method.
Snip code come from onTouchEvent method.
if (inList && !child.hasFocusable()) {
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
.....
}
PerformClick will be call if child.hasFocusable() return false which child is you ListView item view;
Snip code come from hasFocusable method.
#Override
public boolean hasFocusable() {
if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {return false; }
if (isFocusable()) {return true;}
final int descendantFocusability = getDescendantFocusability();
if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i
So solution:
Solution A,set ListView item descendantFocusability property, let its getDescendantFocusability() is not equal FOCUS_BLOCK_DESCENDANTS.
Solution B, ListView item all child views is not hasFocusable( hasFocusable() return false).
you can create View.OnClickListner object which can listen your imagebutton click in getView. onListItemClick generally used to handle row click event not items in rows.
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflator = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View listItem = inflator.inflate(R.layout.medcince_list_item, null);
ImageButton mEdit = (ImageButton)listItem.findViewById(R.id.item_edit);
mEdit.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
// HERE YOU CAN HANDLE BUTTON CLICK. POSITION YOU CAN HAVE FROM getView already.
}
});
mEdit.setTag(getItem(position));
ImageButton mHistory = (ImageButton)listItem.findViewById(R.id.item_history);
mHistory.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
// HERE YOU CAN HANDLE BUTTON CLICK. POSITION YOU CAN HAVE FROM getView already.
}
});
mHistory.setTag(getItem(position));
return listItem;
}
Make the ListFragment implement the View.OnClickListener interface, and implement the code you want to be called when the button are pressed in the method OnClick(View view), which is #Override
I made a custom Listview (Without overriding getView() method) with each item in a Listview having a following Layout
contactlayout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" android:weightSum="1">
<CheckBox android:id="#+id/checkBox1" android:text="CheckBox" android:layout_width="134dp" android:layout_height="108dp" android:focusable="false"></CheckBox>
<LinearLayout android:id="#+id/linearLayout1" android:layout_height="match_parent" android:orientation="vertical" android:layout_width="87dp" android:layout_weight="0.84" android:weightSum="1" >
<TextView android:text="TextView" android:layout_height="wrap_content" android:layout_width="match_parent" android:id="#+id/name" android:layout_weight="0.03"></TextView>
<TextView android:text="TextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="#+id/phone"></TextView>
<TextView android:text="TextView" android:layout_height="wrap_content" android:layout_weight="0.03" android:layout_width="match_parent" android:id="#+id/contactid" android:visibility="invisible"></TextView>
</LinearLayout>
</LinearLayout>
I am populating the Listview using a SimpleCursorAdapter in a following way...
Cursor c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
String from[] = new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone.CONTACT_ID};
int to[] = new int[]{R.id.name,R.id.phone,R.id.contactid};
SimpleCursorAdapter s = new SimpleCursorAdapter(this,R.layout.contactlayout,c,from,to);
lv.setAdapter(s);
On Click of a button I am reading the states of all the Checkboxes. The problem is, if I check one CheckBox several others down the line get automatically Checked. I know this is reusing of Views. How do I avoid it ?. I am not even overriding getView() method in this case, so I wonder if there is still any way to achieve what I want?
Answer
Finally I implemented what #sastraxi suggested...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
final CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkBox1);
final TextView name = (TextView) view.findViewById(R.id.name);
final TextView contactId = (TextView) view.findViewById(R.id.contactid);
final int pos = position;
checkBox.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
if(checkBox.isChecked())
{
checkList.add(String.valueOf(pos));
nameList.add(name.getText().toString());
contactList.add(contactId.getText().toString());
Log.i("Chk added",String.valueOf(pos));
}
else
{
checkList.remove(String.valueOf(pos));
nameList.remove(name.getText().toString());
contactList.remove(contactId.getText().toString());
Log.i("Un Chk removed",String.valueOf(pos));
}
}
});
if(checkList.contains(String.valueOf(pos)))
{
checkBox.setChecked(true);
}
else
{
checkBox.setChecked(false);
}
return view;
}
another way to force not reusing the views, add the following in your cursor adapter:
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public int getViewTypeCount() {
return 500;
}
but yes, you should reuse views whenever possible. In my particular case, I am adding images to my views and without forcing to not reuse the view, they would get re-rendered in the reused views.
Ah, I see what the problem is.
Make a new class that extends SimpleCursorAdapter, say CheckboxSimpleCursorAdapter, and override getView as such:
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.CheckBox1);
checkBox.setChecked(getIsThisListPositionChecked(position));
return view;
}
As you're not using a layout whose top-level View implements Checkable, you have to do everything yourself. That includes clearing state (in this case), as the default implementation re-used a View that was checked--as you correctly intuited.
Edit: use this new code, and implement a protected boolean getIsThisListPositionChecked(int position) method that returns whether or not the item is currently checked (or something like that). I hope I'm being clear enough--you need to figure out if the item should be checked according to your model, and then set that when you create the View.
It's always better to re-use views. What you are trying to achieve can be done with a few tweaks in your code. You need to record the checkedness of your checkboxes by using aanother variable list (a boolean for each list item).
Override these two methods in your Adapter class
#Override
public int getViewTypeCount()
{
return getCount();
}
#Override
public int getItemViewType(int position)
{
return position;
}
I have a list View and In the adaptor of this list View i have a method
public void onItemClick(AdapterView<?> AdapterView, View View,
int position, long id)
each row of list contain 3 view
xml for row is
<?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:background="#android:color/white" android:padding="5dp">
<TextView android:id="#+id/name" android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20dp" android:textStyle="bold" android:textColor="#android:color/black"
android:layout_marginTop="10dp" android:focusable="false">
</TextView>
<TextView android:id="#+id/street"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_below="#id/name"
android:textColor="#android:color/black" android:focusable="false">
</TextView>
<ImageView android:id="#+id/pic" android:src="#drawable/pic"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentRight="true" android:layout_marginRight="10dp"
android:layout_below="#id/name" android:focusable="false">
</ImageView>
</RelativeLayout>
In OnItemClickMethod i want to find click event on these 3 view. how can i do this?
Note: if i am using view.getId() it is returning -1 for first row . so i am unable to use this one.
if(view.getId() == R.id.name){
dotask();
}
Update: I just call onClick method inside getView Method
setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(context,position.toString(), Toast.LENGTH_LONG).show();
}
});
and my problem get solved.
Thanks FunkTheMonk and Vikky.
Here in onItemClick View view refers to RelativeLayout and not textviews according to your xml file.
public void onItemClick(AdapterView<?> AdapterView, View View, int position, long id) {
TextView name = View.findViewById ( R.id.name );
for other views .......
}
You can set an onClickListener on Views inside the row used in a ListView.
abstract class Clicker implements OnClickListener {
int mPosition;
public Clicker(int position) {
mPosition = position;
}
}
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
//inflate
}
//do your stuff
convertView.findViewById(R.id.button1).setOnClickListener(new Clicker(position) {
public void onClick(View v)
{
int row = mPosition;
//button 1 clicked
}
});
convertView.findViewById(R.id.button2).setOnClickListener(new Clicker(position) {
public void onClick(View v)
{
int row = mPosition;
//button 2 clicked
}
});
}
onItemClick gives only the selected row, and provides no touch co-ordinates so you can't manually determine which child has been clicked
You can use view.findViewById on the view you get in onItemClick. It says here ( http://www.vogella.de/articles/AndroidListView/article.html ) that it's a relatively lengthy operation, and that the recommended way is using the view's tag to store its relevant child-views. It seems logical, but it might be premature optimization in your case - depending on the number of uses for your view.