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.
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"
the problems is, that I wan't to make ListView with elements which are containing image, description and two buttons. I'm making them in my own BaseAdapter extension, but fragment which is containing ListView is closing (wihtout errors in logcat..). I've found, that ListView is working well, when I'm not returning layout-type elements. So there is my sample with 'sample linear layout', which is not working.. Is there any possibility, to show layouts in ListView?
Here is my code:
Creating part:
lv = (ListView) getView().findViewById(R.id.main_wall_ambajes_lv);
AmbajAdapter aa = new AmbajAdapter(getActivity().getApplicationContext(), StaticData.ambajes);
lv.setAdapter(aa);
My getView method from adapter:
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout ll = new LinearLayout(getActivity());
ll.setOrientation(LinearLayout.VERTICAL);
ImageView iv = new ImageView(getActivity());
iv.setImageBitmap(placeholderBitmap);
ll.addView(iv);
ll.addView(iv);
ll.addView(iv);
ll.addView(iv);
return ll;
}
I don't know why you don't have any error however I don't think you proceed the correct way.
Usually you create the layout in the xml file of the layout folder and only inflate it in the getView(), for example as follow :
private LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
#Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
view = mInflater.inflate(R.layout.your_custom_layout, parent, false);
}
//your code for setting the image or other things goes here
//for example if you have a textView
TextView textView = (TextView) view.findViewById(R.id.my_textview_id);
textView.setText("my custom text for this cell");
return (view);
}
and your_custom_layout is simply the xml file of your layout.
Note that for performance reason due to cell recycling I only inflate the view when it is null and I only read once the LayoutInflater context and put it in mInflater. However for the best performance you should use a ViewHolder, but it is out of the scope of your question.
My app contains 3 tabs.All the tabs contains List so I have used ListFragment. There is a button in each ListItem. I want to do "something" when "Click" button is clicked within the ListItem as shown in the figure.
How do I implement this. There are tuts about doing same thing for ListActivity but not ListFragment.Thanks in advance. :)
First of all, you need to implement a custom adapter for your ListView. Please, read this article if you are not familiar with this.
Next, you have to disable click on ListView items. If you don't know how, check this out.
Now, in your getView method from your custom adapter, you can find your Button and set up an onClickListener, but only after you have inflated the view for the current ListView position.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.rowlayout, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.label);
textView.setText(values[position]);
Button mButton = (Button) view.findViewById(R.id.my_button_id);
mButton.setOnClickListener(mClickListener);
return rowView;
}
I have a custom dialog which extends Dialog and has a ListView inside its layout. I populate my ListView via a custom adapter which extends ArrayAdapter. Here is my adapter which contains the onClick event for a given list item:
public class PendingTimeslotArrayAdapter extends ArrayAdapter<PendingTimeslot> {
private final Context context;
private final PendingTimeslot[] values;
private final View[] views;
public PendingTimeslotArrayAdapter(Context context, PendingTimeslot[] values) {
super(context, R.layout.mystuff_timeslot_picker_dialog_list_item, values);
this.context = context;
this.values = values;
this.views = new View[values.length];
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(views[position] == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.mystuff_timeslot_picker_dialog_list_item, parent, false);
rowView.setTag((Integer)position);
((TextView)rowView.findViewById(R.id.mystuff_timeslot_picker_list_item_date_time)).setText(values[position].getDateTime());
((TextView)rowView.findViewById(R.id.mystuff_timeslot_picker_list_item_stage_name)).setText(values[position].getStageName());
rowView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("getting touch event");
PendingTimeslot t = values[(Integer)(v.getTag())];
CheckBox checkBox = (CheckBox) v.findViewById(R.id.mystuff_timeslot_picker_list_item_checkbox);
checkBox.setChecked(!checkBox.isChecked());
t.toggle();
}
});
views[position] = rowView;
return rowView;
}
else
return views[position];
}
}
My problem is that when list items are clicked, they do not get touch events, hence my onClick does not get called. Funny thing is, the ListView is fully scrollable and when an item goes out of the visible region and comes back, it becomes touchable and the onClick event is fired.
I tried overriding the ListView and its onTouchEvent method; when an item is clicked, the onTouchEvent on the ListView is really not fired. I also tried overriding the dispatchTouchEvent method and it works correctly, getting all touch events as it is supposed to.
I have used a similar custom ArrayAdapter elsewhere (but not within a Dialog) and it works flawlessly. I am now considering this to be a bug. Am I missing something or should I do this (ListView with clickable items inside a Dialog) another way?
Edit:
Adding
rowView.setClickable(true);
rowView.setFocusable(true);
does absolutely nothing.
Edit2:
Setting an onItemClickListener for my ListView does not work either, even for the items which are scrolled out of and back into the visible region.
Edit3:
I also noticed that when there are 16 items (not a special number) in the ListView, the last 5 items do not get the height I specified (e.g 100px) in the layout I inflate, they behave like wrap_content instead. All in all, I'm starting to believe that a ListView should not be used in a Dialog.
One possible solution I found is to quit trying to use a ListView and instead use a ScrollView with a vertical LinearLayout inside. The layout of this ScrollView is like this:
<ScrollView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" >
<LinearLayout
android:id="#+id/mystuff_timeslot_picker_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
After I get the list data, I inflate a row for each of them and add them to the LinearLayout manually:
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for(PendingTimeslot p : timeslots){
View rowView = inflater.inflate(R.layout.mystuff_timeslot_picker_dialog_list_item, timeslotList, false);
//((TextView)rowView.findViewById(R.id.mystuff_timeslot_picker_list_item_date_time)).setText(values[position].getDateTime());
((TextView)rowView.findViewById(R.id.mystuff_timeslot_picker_list_item_date_time)).setText("just testing");
//((TextView)rowView.findViewById(R.id.mystuff_timeslot_picker_list_item_stage_name)).setText(values[position].getStageName());
rowView.setClickable(true);
rowView.setFocusable(true);
rowView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("just testing");
//PendingTimeslot t = values[(Integer)(v.getTag())];
CheckBox checkBox = (CheckBox) v.findViewById(R.id.mystuff_timeslot_picker_list_item_checkbox);
checkBox.setChecked(!checkBox.isChecked());
}
});
timeslotList.addView(rowView);
}
timeslotList is the LinearLayout I mentioned. This workaround works as expected. Still, I'm feeling very stupid having to use ScrollViews instead of ListViews when they are perfect for the job.
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.