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.
Related
I'm trying to put a button to delete a row of a listview. I've modified the layout of the single rows like this:
With lst.setOnItemClickListener... I manage the click on the row, but I don't know how to click the button inside the list.
It can be done?
Search on google "custom adapter"
Then the 5 first links :
Custom Adapter for List View
http://www.javacodegeeks.com/2013/06/android-listview-custom-adapter-with-imageview.html
http://www.learn-android-easily.com/2013/06/listview-with-custom-adapter.html
http://www.vogella.com/tutorials/AndroidListView/article.html
http://developer.xamarin.com/recipes/android/data/adapters/create_a_custom_adapter_for_contacts/
Override your adapter getview method to handle the button click.
public View getView(final int position, View convertView,
ViewGroup parent) {
LayoutInflater inflater = getLayoutInflater();
View row = inflater.inflate(R.layout.vehicals_details_row, parent,
false);
Button deleteImageView = (Button) row.findViewById(R.id.DeleteImageView);
deleteImageView.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
});
}
}
In your listItem xml layout, set the button to have the following attribute and it will cause the list item to be clickable as well:
android:focusable="false"
I'm using a LinearLayout which contains an ImageView and a HorizontalScrollView as ListView items.
The problem is OnItemClickListener of the ListView doesn't work. After adding android:descendantFocusability="blocksDescendants" on LinearLayout it works when ImageView is clicked but it doesn't work when HorizontalScrollView is clicked.
android:focusable="false" and android:focusableInTouchMode="false" doesn't work too.
I want regular clicks on HorizontalScrollView also fires OnItemClickListener of ListView.
I'm testing on android 4.2.2
I had the same problem and did not find any better solution than just to assign View.onClickListener to descendant of HorizontalScrollView. In my case I needed to know the position value from ArrayAdapter belonging to the clicked listview item, which I passed to the view during the getView execution as a view tag.
RelativeLayout -> HorizontalScrollView -> Relative Layout #+id/clickit ...
public View getView(int position, View convertView, ViewGroup parent)
{
layoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(resourceID, parent, false);
MyType mt = getItem(position);
RelativeLayout rl = (RelativeLayout) rowView.findViewById(R.id.clickit);
rl.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
m_menuEventsListener.onActionsMenuClick(getItem((Integer) view.getTag()));
}
});
rl.setTag(position);
}
Note that the same m_menuEventsListener.onActionsMenuClick is called from the onItemClickListener attached to the listview. m_menuEventsListener is my own listener implemented in the Activity.
I have a List view with a custom adapter (imageviews), in the same activity I have a header and footer, the listView is between those.
What I want is to add a button as the last item of the list view so when you arrive to the last item it appear, i cant add the button outside because it wont scroll
Sorry about my english
Regards
use ListView.addFooterView() to add view as a footer which is visible only in the end of the list:
http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)
If you already have a custom adapter class implemented, the solution is rather simple. Based on an xml layout implemented for your list-view rows which contains both a Button and an ImageView, you can hide/display them in the adapter's getView() method based on the index. This is a code sample, which I currently don't have the chance to test and might not be the most efficient solution, but it should give you an idea:
class CustomAdapter extends SimpleAdapter {
[...]
#Override
public int getCount() {
// number of images to be displayed + 1 for the button
return images.length + 1;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View row = inflater.inflate(R.layout.row, parent, false);
final ImageView imageView = (ImageView) row.findViewById(R.id.image);
final Button button = (Button) row.findViewById(R.id.button);
if (position == getCount() - 1) {
// The last element
imageView.setVisibility(View.GONE);
// set an OnClickListener on the button or whatever...
} else {
button.setVisibility(View.GONE);
// do your regular ImageView handling...
}
return row;
}
}
I am using Custom ListViewAdapter for displaying, well, a list.
Each row in the list has 3 buttons, i.e. listeners attached.
But I am finding it very disturbing, that during each scroll the new OnClickListeners are being created, even for those rows, where convertView exists, as a non-null value.
// The most common approach to convert view, as I understand:
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.listview_item, parent, false);
} else {
view = convertView;
}
final TextView textView = (TextView) view.findViewById(R.id.txtProduct);
textView.setText(name);
textView.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
...
}
});
... two more listeners, with the same approach
return view;
as per my experience with Java, Spider-sense "ting-a-lings" - seems that creating and throwing away the same listener approach is garbage-collector abusing.
I am not sure when the old listener had been collected, if it had...
Is there a way to use the old listener, instead of creating a new one? (some kind of cache data structure)
You can set your List Adapter class to inherit from the View.OnClickListener interface. Then, simply set
textView.setOnClickListener(this);
And handle the click in your adapter class' onClick method. To know, for example, which row is clicked, add this line prior to the one above:
textView.setTag(position);
Then, in onClick, you can know which position in the list you are handling by getting this tag:
public void onClick(View v) {
Object item = myList.get((Integer) v.getTag());
//handle click event
}
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;
}