I have a Gridview filled by an Adapter which returns LinearLayouts each contains an ImageButton and TextView.
In the adapter I am binding an onClick and onLongClick event to the ImageButton.
I am trying to bind OnItemClickListener to the gridview but I don't know why that the onItemclicked never fired up.
It's my 6th hour without anything.
By the way;
OnItemSelectListener working perfectly on the Grid.
I am checking if some piece of code accidentally handles the onItemClicked but couldn't catch yet.
I need help guys.
gridView = (GridView) layoutInflater.inflate(R.layout.gridview, null);
gridView.setOnItemClickListener(new ItemClickListener());
.
.
.
//inner handler class
class ItemClickListener implements AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(mainActivity.getApplicationContext(),view + " clicked at pos " +
i,Toast.LENGTH_SHORT).show();
}
}
Do not use clickable objects in the grid. In that case Android cannot handle the click event of GridView.
Instead, use something to show a similar user interface view. Then handle that object's click actions.
Don't: put Button in the GridView to perform some click actions.
Do: put an ImageView instead of ImageButton and handle ImageView's click events.
If you wants to use Button or ImageButton then you need to write these attributes in your xml code of the widgets.
android:focusable="false"
android:focusableInTouchMode="false"
Its works for me.
But in GridView, Try to avoid use of these widgets. You can use any other widgets in place of these (Like ImageView or any other).
Also make sure, that your ListAdpter returns true for
public boolean isEnabled(int _position)
for the position you want to click.
Hey guyz finally got a solution...
what we were doing is directly accessing the Layout inside the GridView, so the onItemClickListener finds it confusing to access the item.
So the solution is to apply the onClickListener inside the Adapter (i.e. normally ArrayAdapter)
so what i m trying to say is:
public View getView(int position, View convertView, ViewGroup parent) {
//Here row is a view and we can set OnClickListener on this
final View row;
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
//Here we inflate the layout to view (linear in my case)
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ViewHolder();
holder.imageTitle = (TextView) row.findViewById(R.id.text);
holder.image = (ImageView) row.findViewById(R.id.image);
row.setTag(holder);
} else {
row = convertView;
holder = (ViewHolder) row.getTag();
}
ImageItem item = data.get(position);
holder.imageTitle.setText(item.getTitle());
holder.image.setImageBitmap(item.getImage());
//Now get the id or whatever needed
row.setId(position);
// Now set the onClickListener
row.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(context, "Clicked" + row.getId() + "!!",
Toast.LENGTH_SHORT).show();
}
});
return row;
}
Try to set
android:clickable="false"
android:focusable="false"
I meet same problem too, because of several reasons.
So, here's my tips:
Extend BaseAdapter for your adapter;
Use OnClickListener inside the getView in adapter instead setting OnItemClickListener for GridView;
Avoid setting LayoutParams multiple times;
Check if position = 0, don't use convertView, inflate new View;
Set OnClickListener not only for parent View, but for any child View, if any;
Make all your Views clickable.
I just tested it on 4 devices, and this solution works as expected. Hope, it will help in your case.
Correct me, if I made something wrong.
Layout code XML:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#273238"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:padding="1dp">
<ImageView
android:id="#+id/open_image_item_imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/loh"
android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:scaleType="centerCrop"/>
<TextView
android:id="#+id/open_image_item_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:layout_gravity="bottom"
android:padding="4dp"
android:textSize="10sp"
android:ellipsize="start"
android:background="#55000000"
android:textColor="#FFFFFF"
android:text="image name"/>
</FrameLayout>
Adapter code Java:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = null;
if(convertView != null && position != 0)
view = convertView;
else{
view = LayoutInflater.from(getContext()).inflate(R.layout.open_image_item_layout, null, false);
view.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, size));
}
TextView textView = (TextView)view.findViewById(R.id.open_image_item_textview);
ImageView imageView = (ImageView)view.findViewById(R.id.open_image_item_imageview);
...
View.OnClickListener onClickListener = getOnClickListener(files[position]);
view.setOnClickListener(onClickListener);
textView.setOnClickListener(onClickListener);
imageView.setOnClickListener(onClickListener);
return view;
}
Related
In my listview's item, there is a two components.
<TextView
android:id="#+id/owner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:text="방장"
android:layout_centerInParent="true"
android:textColor="#color/colorBlack"
android:textSize="10dp"/>
<ImageButton
android:id="#+id/kickOutBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:visibility="invisible"
android:scaleType="fitCenter"
android:background="#color/colorTransparent"
android:tint="#color/colorBlack"
android:src="#drawable/ic_baseline_close_24"/>
These are in a same location in a view.
I mean, the Textview is located in the center of the ImageButton.
And if the ListView item's target is a manager, I want to make its list item's ImageButton invisible and open the Textview that says manager, and if not, I want to make its list item's ImageButton show the opposite, and I want to make the Textview that says manager invisible. (default is that imagebutton is invisible and textview is visible)
To do that, I tried to this code.
// getView in ListAdapter
#Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
View view;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.navi_list_menu_item, null);
}
else {
view = convertView;
}
TextView supervisor_tv = (TextView) view.findViewById(R.id.owner);
ImageButton kick_btn = (ImageButton) view.findViewById(R.id.kickOutBtn);
if(!mNavItems.get(i).fb_uid.equals(roomSupervisor)) {
kick_btn.setVisibility(View.VISIBLE);
kick_btn.setOnClickListener(v -> {
Log.d("ChatRoomActivity", "click imagebutton");
});
supervisor_tv.setVisibility(View.INVISIBLE);
}
return view;
}
// Activity
mDrawerList = (ListView) findViewById(R.id.nav_list);
mDrawerList.addHeaderView(listHeaderView);
NaviDrawerListAdapter adapter = new NaviDrawerListAdapter(this, mNavItems, roomSupervisor);
mDrawerList.setAdapter(adapter);
mDrawerList.setOnItemClickListener((adapterView, view, position, id) -> {
Log.d(TAG, String.valueOf(position));
});
It is ok to click manager's list item and ImageButton of others.
But the problem is that I cannot click non-manager user's list item.
Could you tell me what is the problem of my code?
By googling, I found the answer.
It is setFocusable and setFocusableInTouchMode
I revised my Adapter code like this.
if(!mNavItems.get(i).fb_uid.equals(roomSupervisor)) {
kick_btn.setVisibility(View.VISIBLE);
kick_btn.setOnClickListener(v -> {
Log.d("ChatRoomActivity", "click a kick btn");
});
kick_btn.setFocusable(false);
kick_btn.setFocusableInTouchMode(false);
supervisor_tv.setVisibility(View.INVISIBLE);
}
Then it works well!
I have trouble with a ListView. Its items (rows) have an ImageButton.
The ImageButton has android:onClick set, so this onClick event is working, but click on row doesn't work.
If I remove the ImageButton from the row item, click on row works (ListView has correct onClick listener). How can I fix it?
I need onClick event when the user clicks on the ImageButton, and the standard click event when the user selects the row (not click the ImageButton but click the row).
My ListView:
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/restaurants_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#color/list_devider"
android:dividerHeight="1dp"
android:cacheColorHint="#color/list_background" />
Unfortunately,
android:focusable="false"
android:focusableInTouchMode="false"
doesn't work for ImageButton.
I finally found the solution here. In your layout xml for those items, add
android:descendantFocusability="blocksDescendants"
to the root view.
It works perfectly for a ListView that has ImageButtons. According to official reference, blocksDescendants means that the ViewGroup will block its descendants from receiving focus.
You can use a custom adapter for your listView (if you haven't already). And there, in the getView(int position, View inView, ViewGroup parent) method of the adapter do something like this:
#Override
public View getView(int position, View inView, ViewGroup parent) {
View v = inView;
ViewHolder viewHolder; //Use a viewholder for sufficent use of the listview
if (v == null) {
LayoutInflater inflater = (LayoutInflater) adaptersContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.list_item, null);
viewHolder = new ViewHolder();
viewHolder.image = (ImageView) v.findViewById(R.id.ImageView);
v.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) v.getTag();
}
.....
viewHolder.image.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//Click on imageView
}i
});
v.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//Click on listView row
}
});
.....
return (v);
}
See here if you need help creating your custom adapter.
If a row of listView have any clickable element like Button , Image..etc..then onItemClick will not work. So you need to write the click listener in getView of your list adapter.
For more read this.
Set these properties for your button:
android:focusable="false"
android:focusableInTouchMode="false"
Or you can set it dynamically in your adapter class:
yourButton.setFocusable(false);
yourButton.setFocusableInTouchMode(false);
And make sure that you set the choice mode as single for the listview:
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
In my case, android:descendantFocusability="blocksDescendants" for main layer did not work, neither in the ListView. I also tried android:focusable="false"
android:focusableInTouchMode="false" which I heard that it is working for Buttons, but I had ImageButton so it didn't.
But setting the properties of the button in the CS file of the Layout worked.
var imageButton = view.FindViewById<ImageButton>(Resource.Id.imageButton1);
imageButton.Focusable = false;
imageButton.FocusableInTouchMode = false;
imageButton.Clickable = true;
If a row has multiple clickable elements, onItemClick() will not work. You will need to set the OnClickListener in the getView() method. Store the listeners the the View's tag so that they can be recycled, add methods to your listeners so they can be specialized for different rows.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
RowClickListeners listeners = (RowClickListeners) view.getTag();
if (listeners == null) {
listeners = new RowClickListeners();
}
// Row click listener:
RowClickListener onClickListener = listeners.rowClickListener;
if (onClickListener == null) {
onClickListener = new RowClickListener();
listeners.rowClickListener = onClickListener;
}
onClickListener.setToPosition(pos);
view.setOnClickListener(onClickListener);
// Overflow listener:
View btn = view.findViewById(R.id.ic_row_btn);
ButtonListener btnListener = listeners.buttonClickListener;
if (rowListener == null) {
btnListener = new ButtonListener(activity);
listeners.rowClickListener = btnListener;
}
btnListener.setToPosition(pos);
btnListener.setCollection(collectionId);
btn.setOnClickListener(btnListener);
}
public static class RowClickListeners {
public RowClickListener rowClickListener;
public ButtonListener buttonClickListener;
}
no single answer above worked for me, but a combination did.
I now set android:descendantFocusability="blocksDescendants" on the ListView and android:focusable="false" android:focusableInTouchMode="false" on the ImageButtons in the XML AND in Java I also set descendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS) on the ListView and focusable(false), focusableInTouchMode(false), clickable(true) on the ImageButtons.
I have a ListView using a custom cursoradapter to fill the ListView.
The row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<LinearLayout
android:orientation="vertical"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent">
<TextView
android:id="#+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="center_vertical"
android:ellipsize="marquee"
android:textSize="24dp" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/artist"
android:singleLine="true"
android:ellipsize="marquee"
android:textSize="14dp" />
</LinearLayout>
<ImageView
android:id="#+id/currentplaying"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginLeft="1dip"
android:src="#android:drawable/ic_media_play"
android:contentDescription="#string/now_playing"
android:visibility="gone" />
</LinearLayout>
As you can see, the ImageView's visibility is gone. I want to make it
visible for one particular row. Here is the code I tried but it is not
working...
View view = getListView().getAdapter().getView(0, null, null);
ImageView iv = (ImageView)view.findViewById(R.id.currentplaying);
iv.setVisibility(ImageView.VISIBLE);
Thanks in advance.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView==null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.yourlayout, null);
holder.imgViewLogo = (ImageView) convertView.findViewById(R.id.imgViewLogo);
convertView.setTag(holder);
}
else {
holder=(ViewHolder)convertView.getTag();
}
if(position==0) {
holder.imgViewLogo.setVisiblity(View.VISIBLE);
}
return convertView;
}
EDIT:
I got it working. I used this to start the ListView activity.
intent.putExtra("id", c.getInt(c.getColumnIndex(DatabaseHelper._ID)));
startActivity(intent);
In the ListView activity,
currentplayingid = getIntent().getExtras().getInt("id");
Then I added this in bindview()
ImageView imgview = (ImageView)view.findViewById(R.id.currentplaying);
int id = c.getInt(c.getColumnIndex(DatabaseHelper._ID));
if (id == SongsListActivity.this.currentplayingid)
imgview.setVisibility(View.VISIBLE);
else
imgview.setVisibility(View.GONE);
I got it working. I used this to start the list view activity.
intent.putExtra("id", c.getInt(c.getColumnIndex(DatabaseHelper._ID)));
startActivity(intent);
In the listview activity,
currentplayingid = getIntent().getExtras().getInt("id");
Then i added this in bindview()
ImageView imgview = (ImageView)view.findViewById(R.id.currentplaying);
int id = c.getInt(c.getColumnIndex(DatabaseHelper._ID));
if ( id == SongsListActivity.this.currentplayingid )
imgview.setVisibility(View.VISIBLE);
else
imgview.setVisibility(View.GONE);
perhaps you should do it in getView() of your adapter
EDIT:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
// codes...
if (position == 0)
{
holder.imgViewLogo.setVisibility(ImageView.VISIBLE);
}
else
{
holder.imgViewLogo.setVisibility(ImageView.GONE);
}
// codes...
}
You have to do it like this
iv.setVisibility(View.VISIBLE);
If it is working some time then may be i can help you. What happen that whenever you move you listview it recreates all views again in this case it never save the last state of view. So what you need to do is to save state of your each imageview and in getView() you have to set accordingly.I am posting one of my answer it may help you.
Here is a little code for your help: I will create a boolean arraylist.
private ArrayList imageview_visible = null;
Then I will set states of all imageview as false in my constructor:
for (int i=0; i < no_of_elements.size(); i++) {
imageview_visible.add(i, false);
}
In your getView write this code:
public View getView (int position, View convertView, ViewGroup parent)
{
//WRITE YOUR CODE
if (imageview_visible.get(position) == true)
{
//SET YOUR IMAGE VIEW AS VISIBLE
} else {
// SET IMAGEVIEW AS GONE
}
}
Whenever you unhide or hide your view just save it into imageview_visible.set(true or false) this will save state of you all imageview and set every image view accordingly
Use LayoutInflater to get view object
LayoutInflater inflater = this.getLayoutInflater();
View rowView = inflater.inflate(R.layout.row, null, true);
ImageView iv = (ImageView)view.findViewById(R.id.currentplaying);
iv.setVisibility(ImageView.VISIBLE);
Try the following code as follows,
private class ViewHolder
{
ImageView imgViewLogo;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
if(convertView==null)
{
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.yourlayout, null);
holder.imgViewLogo = (ImageView) convertView.findViewById(R.id.imgViewLogo);
convertView.setTag(holder);
}
else
{
holder=(ViewHolder)convertView.getTag();
}
if(position==0)
{
holder.imgViewLogo.setVisiblity(View.VISIBLE);
}
return convertView;
}
It Works for me...It may help you.
I ran into similar problems where several widgets would appear for some rows but not for others. The problems were due to view recycling. I'm not exactly sure if that's your issue here, but you should handle it anyway. The trick is to set visibility for every row; instead of just for the row that you want to appear/disappear.
So:
if (position == 0)
{
iv.setVisibility(ImageView.VISIBLE);
}
else
{
iv.setVisibility(ImageView.GONE);
}
Otherwise, you're assuming that for positions other than 0 the visibility is GONE but that might not be the case with view recycling. I do this work in bindView, by the way. Not sure if that's technically correct.
I have the same issue... i solved with a non standar solution, but worked for me...
v.setImageResource(R.color.transparent);
importing R from android
import android.R;
Both iv.setVisibility(View.VISIBLE); and iv.setVisibility(ImageView.VISIBLE); are correcte but It's better to use View instead of ImageView because VISIBLE & GONE are defined in View class.
You most change Both Visibility (VISIBLE or GONE) in that if. like:
if(?)
iv.setVisibility(View.VISIBLE);
else iv.setVisibility(View.GONE);
You can hide or show views using setVisibility(int) .
use iv.setVisibility(View.VISIBLE);
I have a custom view for each row in a custom ListAdapter and I am trying to perform onClick action and get the row position in the list where the click came from.
<?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:paddingLeft="10dip" android:id="#+id/itemRoot" android:clickable="false">
<TextView android:layout_width="wrap_content" android:text="TextView"
android:layout_height="wrap_content" android:id="#+id/itemTxt"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"></TextView>
<TextView android:layout_toRightOf="#+id/itemTxt" android:text="TextView"
android:layout_height="wrap_content" android:layout_alignBottom="#+id/itemTxt"
android:id="#+id/amountTxt" android:paddingLeft="6dip"
android:layout_centerVertical="true" android:layout_width="match_parent"></TextView>
<ImageView android:id="#+id/delBtn" android:layout_height="wrap_content"
android:src="#drawable/delete" android:layout_width="wrap_content"
android:layout_alignParentRight="true" android:paddingRight="10dip"
android:layout_centerVertical="true"></ImageView>
</RelativeLayout>
I want to figure out when TextView or ImageView is clicked, I also need to know what row in the list it came form. I have tried using OnItemClickListener and it works fine to get the row where the click comes from. However, once I register an OnClick listener for the views, the onItemClicked() method gets skipped and onClick() is executed straight away, but there is no way of getting the row position that the view is in(or at least not that I know if).
If I set clickable to false for the views, then onItemClicked get called and I tried manually calling performClick() on the given view. But this only works for the root element (RelativeLayout), and if click comes from TextView inside the layout the click doesn't propagate.
I can't really figure out how to get both position in the list and perform onClick action.
Any thoughts are welcome.
Alex
You could assign the proper OnClickListener to each ImageView and TextView from inside your ListAdapter's overridden getView method.
Inside that method you know the item's position, so you can pass it to the custom listener classes, and use it there as you want:
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
// TODO: instantiate the layout
// here I call a super method
final View view = super.getView(position, convertView, parent);
final TextView textView = (TextView)view.findViewById(R.id.itemTxt);
textView.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Log.i("Click", "TextView clicked on row " + position);
}
});
final ImageView imageView = (ImageView)view.findViewById(R.id.delBtn);
imageView.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Log.i("Click", "ImageView clicked on row " + position);
}
});
return view;
}
The other possible option to have the OnClickListener in the same class as the creating activity is to add to the activity implements OnItemClickListener.
public class DisplayListCustom extends Activity implements OnItemClickListener
Then set the custom list to listen
ListView list = (ListView)findViewById(R.id.custom_list);
list.setClickable(true);
list.setOnItemClickListener(this);
list.setAdapter(new CustomListAdapter(getApplicationContext(), listItems));
Finally in the onItemClick return, you can find the inner views by using resource ID
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
LinearLayout listItem = (LinearLayout) v;
TextView clickedItemView = (TextView) listItem.findViewById(R.id.name);
String clickedItemString = clickedItemView.getText().toString();
Log.i("DisplayListCustom", "Click detected " + clickedItemString + ", position " + Integer.toString(position));
This is the solution I went with. I used LinearLayout for my custom layout container, but I assume the same applies to RelativeLayout.
You need to extend your TextView etc, override the click method, do the appropriate actions and then the trick is to return false so it's then propagated to the listview.
I've seen example com.example.android.apis.view.List11 from ApiDemos. In that example, each row takes the view android.R.simple_list_item_multiple_choice. Each such view has a TextView and a CheckBox.
Now I want each view to have 2 TextViews and 1 CheckBox, somewhat similar to the List3 example. I tried creating a custom layout file row.xml like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<CheckBox
android:id="#+id/checkbox"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="fill_parent" />
<TextView
android:id="#+id/text_name"
android:textSize="13px"
android:textStyle="bold"
android:layout_toLeftOf="#id/checkbox"
android:layout_alignParentLeft="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/text_phone"
android:textSize="9px"
android:layout_toLeftOf="#id/checkbox"
android:layout_below="#id/text_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
Then in Activity's onCreate(), I do like this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Query the contacts
mCursor = getContentResolver().query(Phones.CONTENT_URI, null, null, null, null);
startManagingCursor(mCursor);
ListAdapter adapter = new SimpleCursorAdapter(this,
R.layout.row,
mCursor,
new String[] { Phones.NAME, Phones.NUMBER},
new int[] { R.id.text_name, R.id.text_phone });
setListAdapter(adapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
The result kind of looks like what I want, but it looks like the list doesn't know which item of it is selected. Also, I need to click exactly on the CheckBox. In the List11 example, I only need to click on the item row.
So what do I need to do to make a multiple choice list with my custom view for each row? Many thanks.
You have to make your own RelativeLayout that implements the Checkable interface and have a reference to the CheckBox or to the CheckedTextView (or a list if it's multiple choice mode).
Look at this post:
http://www.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/
The answer of Rahul Garg is good for the first time the list is loaded, if you want some rows to be checked depending on the model data, but after that you have to handle the check/uncheck events by yourself.
You can override the onListItemCLick() of the ListActivity to check/uncheck the rows
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
ViewGroup row = (ViewGroup)v;
CheckBox check = (CheckBox) row.findViewById(R.id.checkbox);
check.toggle();
}
If you do so, do not set the ListView to CHOICE_MODE_MULTIPLE, because it makes strange things when calling the function.
To retrieve the list of checked rows, you have to implement a method yourself, calling getCheckItemIds() on the ListView does not work:
ListView l = getListView();
int count = l.getCount();
for(int i=0; i<count; ++i) {
ViewGroup row = (ViewGroup)l.getChildAt(i);
CheckBox check = (Checked) row.findViewById(R.id.ck1);
if( check.isChecked() ) {
// do something
}
}
Each such view has a TextView and a
CheckBox.
No, it doesn't. It has a CheckedTextView.
So what do I need to do to make a
multiple choice list with my custom
view for each row?
Try making the CheckBox android:id value be "#android:id/text1" and see if that helps. That is the ID used by Android for the CheckedTextView in simple_list_item_multiple_choice.
The solution is to create a custom View that implements the Clickable interface.
public class OneLineCheckableListItem extends LinearLayout implements Checkable {
public OneLineCheckableListItem(Context context, AttributeSet attrs) {
super(context, attrs);
}
private boolean checked;
#Override
public boolean isChecked() {
return checked;
}
#Override
public void setChecked(boolean checked) {
this.checked = checked;
ImageView iv = (ImageView) findViewById(R.id.SelectImageView);
iv.setImageResource(checked ? R.drawable.button_up : R.drawable.button_down);
}
#Override
public void toggle() {
this.checked = !this.checked;
}
}
And create a custom layout for the list items using the new widget.
<?xml version="1.0" encoding="utf-8"?>
<ax.wordster.OneLineCheckableListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:background="#drawable/selector_listitem"
android:orientation="horizontal" >
<ImageView
android:id="#+id/SelectImageView"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="#drawable/button_friends_down" />
<TextView
android:id="#+id/ItemTextView"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:gravity="center"
android:text="#string/___"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#color/text_item" />
</ax.wordster.OneLineCheckableListItem>
Then create a new custom Adapter using the layout above.
It is possible by some trick
in your ListActivtyClass in method
protected void onListItemClick(ListView l, View v, int position, long id) {
//just set
<your_model>.setSelected(true);
}
now in you custom Adapter
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(textViewResourceId, parent, false);
}
if (<your_model>.isSelected()) {
convertView.setBackgroundColor(Color.BLUE);
} else {
convertView.setBackgroundColor(Color.BLACK);
}
return convertView;
}
this way you can customize the view in adapter when the item is selected in the list.
Simple example how to get a custom layout to work as custom checkbox:
private class FriendsAdapter extends ArrayAdapter<WordsterUser> {
private Context context;
public FriendsAdapter(Context context) {
super(context, R.layout.listitem_oneline);
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final int pos = position;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rv = inflater.inflate(R.layout.listitem_oneline, parent, false);
rv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
boolean checked = friendsListView.isItemChecked(pos);
friendsListView.setItemChecked(pos, !checked);
}
});
WordsterUser u = getItem(position);
TextView itw = (TextView) rv.findViewById(R.id.ItemTextView);
itw.setText(u.userName + " (" + u.loginName + ")");
ImageView iv = (ImageView) rv.findViewById(R.id.SelectButton);
if (friendsListView.isItemChecked(position)) {
iv.setImageResource(R.drawable.downbutton);
} else {
iv.setImageResource(R.drawable.upbutton);
}
return rv;
}
}
I found it very useful this little code: http://alvinalexander.com/java/jwarehouse/apps-for-android/RingsExtended/src/com/example/android/rings_extended/CheckableRelativeLayout.java.shtml
It is a great addition to #ferdy182 's http://www.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/ content.
Got the solution ... You can get the clicks on the views (like checkboxes in custom layouts of row) by adding listener to each of them in the adapter itself while you return the converted view in getView(). You may possibly have to pass a reference of list object if you intent to get any list specific info. like row id.
I want to confirm that the Pritam's answer is correct. You need an onClickListener on each list's item (define it in the adapter's getView()).
You can create a new onClickListener() for each item, or have the adapter implement onClickListener() - in this case the items must be tagged for the listener to know, which item it is operating on.
Relying on the list onItemClickListener() - as someone advised in another thread - will not work as the CheckBox will intercept the click event so the list will not get it.
And finally #Rahul and JVitella:
The situation is that the CheckBox on a list item must be clickable and checkable independently from the list item itself. Therefore the solution is as I just described above.