I'm using android:checkableBehavior="single" within a group, this group contains few items, those items represents content filters, there is no default filter(meaning there is not always has to be a checked item, at least that what I wants), if I click a filter and want to disable it I can click it again and my expectation is that by using setChecked(false) the item will unchecked.
However, it looks like:
For checkableBehavior="single" setChecked() will always check the menu
item even if parameter is 'false' because of Google implementation.
My obvious solution is adding a no filter item that can be checked by the users to indicates they don't want a filter but it's just seems more intuitive to check and uncheck the same item, it there another way to setChecked(false)?
Google's brain-dead implementation in MenuItemImpl (as of Nougat):
#Override
public MenuItem setChecked(boolean checked) {
if ((mFlags & EXCLUSIVE) != 0) {
// Call the method on the Menu since it knows about the others in this
// exclusive checkable group
mMenu.setExclusiveItemChecked(this);
} else {
setCheckedInt(checked);
}
return this;
}
Note that checked is completely ignored when the EXCLUSIVE flag is set.
Related
I am implementing a custom recyclerview with switch for item selection. I have a "Select All" option at the right corner of App Bar (top bar). I want to allow user to use Select All option and also allow individual item selection in recyclerview.
I don't know how to implement individual selection along with Select All. When an item is deselected after using the select all option and when the list is scrolled the item gets selected automatically as the isSelectedAll flag is set true in onBindViewHolder method in the below code.
******SELECT ALL CLICK LISTENER IN ACTIVITY CLASS******
mBinding.imageViewActionSelect.setOnClickListener(v -> {
mAdapter.selectAll();
});
******ADAPTER CLASS******
public void selectAll() {
isSelectedAll = true;
notifyDataSetChanged();
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
if (isSelectedAll) {
holder.mSwitchView.setChecked(true);
}
else
holder.mSwitchView.setChecked(false);
}
First, Add one variable isSelected to your POJO class and then, while you select All option, make that variable true by running your list of items in a loop, and then call adapter.notifyDataSetChanged(). Now when you select or deselect individual items make that isSelected variable true or false according to your needs and dont forget to call notifyDataSetChanged(). You are good to go.
You could use this FastAdapter library: https://github.com/mikepenz/FastAdapter . Single select is easy, its already done for you. For multi select, you could just loop through all your items and call mAdapter.toggleSelection(position) . When you need the selected items you could easily call mAdapter.getSelection() . Its that easy, no need to do stuff yourself
I have columns of checkboxes, the top row of which are CheckAll checkboxes for that particular column. If I uncheck the Checkall from the first CheckAll checkbox in the leftmost column I would like to uncheck the remaining CheckAll checkboxes.
However the mycheckbox.setSelected(false) has no effect. If however, I do a mycheckbox.setEnabled(false) (just as a test) it DOES work and the checkbox is disabled.
By the way, this is a "header row" for a listview with a custom adapter. The contents of the listview work as expected.
Any idea how to get the checkbox unchecked?
You should use mycheckbox.setChecked(false) instead of setSelected.
I've tried searching for setSelected to see what it does, but in official documentation of the CheckBox, I was not able to find it (which suggested to me that this method is probably found in one of the parent classes of CheckBox). Tried typing it in Android Studio:
CheckBox cb = new CheckBox(getApplication());
cb.setSelected(true);
Went to the implementation of the method (CTRL+Click) and saw this in the TextView class, from which almost every other widget is derived:
#Override
public void setSelected(boolean selected) {
boolean wasSelected = isSelected();
super.setSelected(selected);
if (selected != wasSelected && mEllipsize == TextUtils.TruncateAt.MARQUEE) {
if (selected) {
startMarquee();
} else {
stopMarquee();
}
}
}
Interesting thing to note here is that setChecked method is contained in the CompoundButton class, while setSelected is is TextView. That means that setSelected does something completely different because textView surely cannot be checked/unchecked.
I hope this explains it well.
I have a list with items that have checkBox, and I need that only one checkBox to be selected at a time. I cannot use listView with singleChoice nor RadioButtons. Below is my code I am using but I do not know why is not working.
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (selectedCheckBox != null) {
// simulate radio group behavior
selectedCheckBox.setChecked(false);
selectedCheckBox = null;
}
if (isChecked) {
selectedCheckBox = (CheckBox) buttonView;
}
}
The problem is that the checkBoxes still remain checked and I do not know why regarding that I set the previous selectedCheckBox to false. Could anyone explain what happens? Thanks
UPDATE
I tested on a Nexus 5 with Android 5.0 and it works on that. On Android versions < 5.0 seems to have the problem I mentioned.
You need to call: notifyDataSetChanged() of your ListView Adapter. If not your data in your ListView is not going to refresh and your checkboxes will remain selected.
If you have one checkbox in each ListView item, you must loop the entire "other" (that must be unchecked) items, and uncheck it. It's not a practical approach.
I usually use a Arraylist to fill Listview. In array list there must be objects like boolean fields. So when a checkbox is checked or unchecked it means that the boolean field is changed to false or true, and then the list view is reproduced. If you follow this way, then it must be easy, first loop through Arraylist and change all booleans to false, then change the selected one to true, that is all, then android will refresh view for you. Hope it help.
My problem is - I've got an ExpandableListView and want to use Contextual Action Bar (CAB) on it's child items. The bad thing is - the group items are also get selected by long-click, which is bad for me. So is there any way to make them non-selectable while in ActionMode?
I tried to use onItemLongClick; tried onLongClick inside getGroupView. Tried some other tricks but failed.
If you find this impossible - maybe there is a way to make all the child items within the selected group be selected as well? That could be a solution, but I could not do that niether.
Thank you.
Solved.
What I did is the next:
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
boolean checked) {
int type = ExpandableListView.getPackedPositionType(id);
if (checked && type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
elvBankBranches.setItemChecked(position, false);
return;
}
}
When item is checked - I check if it is a grouop - and if it is - just uncheck it. Works fine.
Note! - when uncheck the item in code - this method onItemCheckedStateChanged will be triggered once again!
Hope it helps someone )
I have an unusual issue with my ListView. I currently have a "deselectAll()" method which iterates through the items in my ListView and sets them to unchecked (the items implement the Checkable interface). The "checked" variable gets changed correctly (the view reports as not being checked), but the visual indicator (in this case, a background change) does not show the view as unchecked (the background stays the color of a checked item).
I am iterating and deselecting through my listview like so (I also added my declerations):
private ListView vw_entryList;
private void deselectAll() {
for (int i = 0; i < sAdapter.getCount(); i++) {
((Entry)vw_entryList.getItemAtPosition(i)).setChecked(false);
}
}
The code for my implemented setChecked() is as follows:
public void setChecked(boolean checked) {
_checked = checked;
if (checked) {
setBackgroundResource(R.drawable.listview_checked);
}
else {
setBackgroundResource(R.drawable.listview_unchecked);
}
invalidate();
}
It should be noted that when the items are clicked, they are toggled between checked and unchecked in the OnItemClickListener, and this works ok, with the background change and everything. The code for toggling is very similar:
public void toggle() {
_checked = !_checked;
setBackgroundResource(_checked ?
R.drawable.listview_checked : R.drawable.listview_unchecked);
invalidate();
}
The only difference I can see is where the methods are called from. toggle() is called from within the OnItemClickListener.onClick() method, while my deselectAll() is called from within a button's standard OnClickListener, both in the same class. Does anyone have any ideas as to why the background doesn't change when I call my deselectAll() function?
Do you have custom, non-standard color for the background? If so you might take a look at http://www.curious-creature.org/2008/12/22/why-is-my-list-black-an-android-optimization/ - it boils down to setting android:cacheColorHint attribute of your list to the background color. Maybe that will help.
Edited after further discussion:
I think you need to call getAdapter().notifyDataSetChanged() on the List rather than invalidate(). List is really build in the way that it is relying on adapter to provide the data. What you are doing in fact you have an implicit adapter - Entry is really kept in the adapter and by setting checked, you are changing the data model really, but if you do not call notifyDataSetChanged() the list does not really know that the model has changed and will not recreate the views (invalidate() will only redraw the existing ones).
After trying everything (thanks for your help Jarek), I found a solution that works for my purposes. Instead of implicitly calling the setChecked() within the view that was clicked, I leave it up to the setItemChecked() method within the ListView class.
My updated code:
private void deselectAll() {
for (int i = 0; i < sAdapter.getCount(); i++) {
vw_entryList.setItemChecked(i, false);
}
}
My best guess is that the ListView knows that its items implement the Checkable class, and thus requires itself to be the handler of all item operations. Something along those lines. If anyone can explain in more detail why this solution works while the others did not, I'll reward them with the answer and an upvote.