I'm trying to put a checkbox into ExpandableListView. How do I do that? I extend BaseExpandableListAdapter and put the following into getGroupView():
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
View view = convertView == null ?
context.getLayoutInflater().inflate(R.layout.onet_head, null) : convertView;
((TextView)view.findViewById(R.id.onetText)).setText(cats.get(groupPosition).value);
return view;
}
Notice that inflated layout? That's where I'm putting TextView and CheckBox.
I noticed that placing a checkbox into my group row layout disables default group row functionality when clicking on the row makes a secondary (child) list appear. CheckBox is functioning as expected but when I click outside of the it the
click is never detected by ether CheckBox or by OnGroupClickListener. I suspect that placing CheckBox into group row this way interferes with event detection/handling but thus far I'm not able to track it down
Can
someone help me to resolve this?
The CheckBox works fine though including detecting clicks when
clicking directly on the box
Anytime you place an item that is focusable in a list the list items no longer respond to clicks or anything like that. For every item you place in the list item that is focusable (buttons, checkboxes, etc), you need to set the android:focusable attribute to false.
I had a similar question and that was the answer for me.
Android custom ListView unable to click on items
Related
I have an ExpandableListView with a group header that shall expand and collapse when clicked. This works for clicks on an ImageView that is inside the list item and it works on directly clicking the item and so on but it doesn't work for a TextView in the list item.
I have to give the TextView a OnClickListener and catch the click separately. This is not nice especially because I don't have all data that I normally get in the OnGroupClickListener.
I read about making the TextView clickable=true and focusable=false but this didn't help. What else will I have to set or change to make the click go "through" the TextView to the base view?
Edit
see my answer for the reason.
Anyway I show how the GroupClickListener is set.
And of course clickable is set to true, not false.
In my activity that displays this list I do this
ExpandableListView.OnGroupClickListener groupClickListener = new ...() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
if (parent.isGroupExpanded(groupPosition))
parent.collapseGroup(groupPosition);
else
parent.expandGroup(groupPosition, true);
return true;
}
};
then assign this to the expandable listview.
listView.setOnGroupClickListener(groupClickListener);
The solution is pretty clear now as I found it.
I did set android:inputType="textNoSuggestions" what I found as advice because I sometimes experienced the TextView to show underlines as an indicator of spelling mistakes.
Probably this sets the view in focusable mode which captures the click.
I have to find out what's the deal with those underlines. Why only sometimes? Why at all? They are pretty stupid for an element that shall not accept any input but simply display static text.
But at least I found it and I hope this can help others to save some time.
Before marking this question duplicate, I know there are few threads going on this particular topic but they are few years old (2012-13) and the Android APIs have changed since then. Furthermore, I have tried those resolutions but either they are not working anymore or since I have bound my ExpandableListView with an ExpandableListAdapter (extending BaseExpandableListAdapter), the solutions are not working.
Here is my problem:
I have one ExpandableListView fetching data from static file with the help of ExpandableListAdapter extending BaseExpandableListAdapter.
I have implemented getChildView() and getGroupView() methods within the adapter to show the Group Items and Child Items.
What I am not able to achieve is the smooth auto scrolling of the selected clicked item to the top. Something like this: Auto scrolling in ExpandableListView
The solution listed in above thread (ListView.setSelection(position)) is not working in my case. I have tried it. Similarly solution like (android:transcriptMode="disabled or smoothScroll or normal") or (ExpandableListView.smoothScrollToPositionFromTop(scrollTo, 0)) are not giving the desired results. I am not sure what wrong. There is no error or warning or anything.
There are few threads that says to call your ExpandableListView in onGroupExpand() method of the adapter. First, this method is no longer there but I suppose they are referring to the now getChildView() method. But here the items are fetched from the View convertView which is the XML layout of the child items and I don't have ExpandableListView in this layout. I have it in my MainActivity.
Maybe I am getting confused somewhere for this simple issue. Can someone please guide what I am missing and how I can achieve the desired results?
I had the same problem. In child i had only one TextView, which was binded. The point of all was, that in the moment of scrolling to "expanded group" was height of this TextView unknown, due to binding. Text was setted later. So, i set that manually in my adapter:
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
InfoModelView info = (InfoModelView) getChild(groupPosition,childPosition);
SubitemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(this.context),R.layout.elv_child, parent, false);
if (info != null){
binding.setInfo(info);
binding.lblListItem.setText(info.getDescription());
}
return binding.getRoot();
}
I thing, now i don't need no more all that staff around binding.
Currently, I have a ListView row. Clicking any area on the row, will yield ListView click events.
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
this.getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
this.getListView().setMultiChoiceModeListener(new ModeCallback());
this.getListView().setOnItemClickListener(new ListViewOnItemClickListener());
} else {
// http://stackoverflow.com/questions/9754170/listview-selection-remains-persistent-after-exiting-choice-mode
this.getListView().setOnItemLongClickListener(new ListViewOnItemLongClickListener());
this.getListView().setOnItemClickListener(new ListViewOnItemClickListener());
}
Now, for each row, I would like to add a small button. Clicking on the small button will yield button click event, which is different from ListView original click event.
In my ArrayAdapter, I use to have
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = activity.getLayoutInflater();
rowView = inflater.inflate(R.layout.watchlist_row_layout, null);
...
}
Button button = (Button)rowView.findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Utils.showLongToast("BUTTON CLICK");
}
});
Clicking on the button will yield button click event. However, clicking on area other than button, will not yield any ListView click event anymore.
May I know why is it so? Is there any way to resolve this?
If you want to make both Rows and Buttons clickable, set
android:focusable="false"
for your Button. The same goes for ImageButtons, RadioButtons, ...
Android has been primarily designed for a large set of input methods.
The entire system is completely capable of working with no touch
screen. To navigate through the UI, the user can use a directional pad
which focuses Views after Views if and only if those Views are
focusable. By default, all Android controls are focusable. In order to
prevent having controls that are not focus-reachable, the ListView
will simply prevent the selection (and click) of an itemview. By
design, the ListView blocks clicks of itemview containing at least one
focusable descendant but it doesn’t make the content focus-reachable
calling setItemsCanFocus(true).
Here is the whole great explaination: Having several clickable areas in a ListView
It's worth noting that the preferred way (even according to the link provided in the accepted answer) is to set the android:descendantFocusability attribute to block focus from the root layout you're inflating within the adapter. There can be potential situations where simply setting the focusable attribute to false on an individual element won't solve the problem, but the descendantFocusability attribute will.
I have a list of around 2500 items in a ListView object. I would like for some of those items to be visible, but greyed out. An activity launches for the ones that aren't greyed out (in my case, this is an AlertDialog). I'd like (for example) the first 500 items to be active and to have the usual behaviour, whilst the other items are greyed out and clicking on them does nothing.
What I'm trying to create is a trial version of a ListView app, so that the user can only access some of the items in the list for demonstration purposes.
What would be the simplest way of going about this? I can only think of having two lists that are appended to each other (the first being active, the second not). Ideally I would actually have interdigitated lists, such that (for example) every third item is active and the others are not, but I'll settle for two separate groups that run on the same list if that would be too complicated.
Simply extend whatever adapter you are using and add this simple check in getView():
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if(position < 500) {
view.setClickable(false);
view.setEnabled(true);
}
else {
view.setClickable(true);
view.setEnabled(false);
}
return view;
}
I did your simple check (if the row is in the first 500) then changed a couple characteristics.
setEnabled() turns the text grey when it is false.
setClickable() when true this prevents the ListView from receiving the TouchEvent.
Hope that helps!
I've populated a ListActivity from a Cursor using SimpleCursorAdapter that starts another activity when one of the list items have been clicked. I'm also using ViewBinder to do some custom transformation of the data.
I want to add a CheckBox to each row in the list so I've changed the view and added a CheckBox with gravity right.
Adding the CheckBox has removed the ability to click on the items. The onListItemClick method I was overriding in ListActivity is no longer called when you press on a list item. Removing the CheckBox fixes this. Why is this?
Also, how can I set up the list so that it continues to perform my required functionality if the main part of the list item is clicked but have additional functionality when the CheckBox in the item is checked? Will setting a onCheckedChangedListener work or is the same view instance reused for each item in the list?
As explained here, the click listener only works if no other view is focusable. Setting your CheckBox to focusable="false" should do the trick:
<CheckBox android:focusable="false" />
Looks like SimpleCursorAdapter is too primitive for what I wanted to achieve.
I've switched to implementing CursorAdapter and returning a new view using the LayoutInflater in my implementation of the newView method.
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.alarm_row, parent, false);
}
In bindView I then set a custom OnClickListener to my main LinearLayout and then another OnCheckedChangeListener to the CheckBox.
For all this to look right I had to set the LinearLayout's background to android's menuitem drawable:
android:background="#android:drawable/menuitem_background"