I am using an ExpandableListView. It works fine, but I want to add an OnGroupExpandListener;
The problem is if I override it, the 'basic' default behaviour for that is overridden as well. I basically want something like this:
mTeamListAdapter = new TeamListAdapter(getLayoutInflater());
mTeamList = (ExpandableListView) findViewById(R.id.screen_team_teamslist);
mTeamList.setAdapter(mTeamListAdapter);
mTeamList.setGroupIndicator(null);
mTeamList.setOnGroupExpandListener(new OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
// do my stuff..
// something like "super();" to enable the other default behaviour
}
});
Specifically, I want to make a Button visible (and clickable - it is "android:visibility="gone" before) on each group in the ExpandableListView. I still want each group, and its children, to be clickable as well!
How do I do this?
EDIT: By "basic default behaviour", I mean that if I override that method (OnGroupExpand) it seems I cannot expand/collapse the groups anymore!
The assertion that "the 'basic' default behaviour is overridden" when an OnGroupExpandListener is set is not correct.
You can verify it by looking at the source code for ExpandableListView (see the handleItemClick method):
http://codesearch.google.com/codesearch#uX1GffpyOZk/core/java/android/widget/ExpandableListView.java&q=package:android.git.kernel.org%20file:android/widget/ExpandableListView.java&l=1
Are you sure you haven't set a OnGroupClickListener? This WILL override group expansion if its OnGroupClick implementation returns true (i.e. the click is deemed to be handled).
Either that, or something in your specific OnGroupExpand implementation is affecting the data that your ExpandableListAdapter uses to display the child rows for the groups.
Related
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.
I have been experiencing a problem with my custom adapter and have located the problem solution. However I do not know how to go about it. I have researched and seen a few examples of a listview custom adapter at which buttons are given tags like viewHolder.button.setTag(Tag) and I understand what the tag does but I am unsure as to how to use it. My questions are: When I set the tag on a button, how does the application differentiate my buttons from another if all the tags are set the same? Also, say I have an onClick method in my custom adapter, how do I use the tag that I set to the button to identify the button that was clicked? I've kind of seen similar adapters on the internet but not exactly , a link to an example would be greatly appreciated also.
I am unsure as to how to use it
tag is a mechanism to make your views remember something, that could be an object an integer a string or anything you like.
My questions are: When I set the tag on a button, how does the
application differentiate my buttons from another if all the tags are
set the same?
i do not understand this question but i think if you notice that your button has a memory and it calls tag you can use it in a better way. if all of your buttons memory(tags) are the same so you can not use tags to distinguish the buttons you must use ids.
say I have an onClick method in my custom adapter, how do I use the
tag that I set to the button to identify the button that was clicked?
you must set different tags for your buttons or grouped them logically and set different tags for each group then in your onClick method use the tags to identify your buttons group:
OnClickListener myButtonListener = new OnClickListener() {
#Override
public void onClick(View arg0) {
Object obj = arg0.getTag();
if(obj instanceOf groupOneTagObject){
// do action for group 1
}else if(obj instanceOf groupTwoTagObject){
// do action for group 2
}
}
});
I'm trying to implement this using Google's Espresso, however I'm not finding any ViewAssertion or ViewAction that'd allow me to do this.
I'm not sure if these can be done using bundled in matchers or should I write my own.
Thanks!
Even though #denys answer seemed to be correct at first glance, it looks like it works only on certain cases (as suggested by Espresso author). The proper way to scroll to an specific item is as replied here on android-test-kit-discuss forum, and reproduced below:
onData(instanceOf(Item.class))
.inAdapterView(allOf(withId(android.R.id.list), isDisplayed()))
.atPosition(9)
.check(matches(isDisplayed()));
It could look something like this:
1. Find the number of elements in listView and save it in some variable:
final int[] counts = new int[1];
onView(withId(R.id.some_list_view)).check(matches(new TypeSafeMatcher<View>() {
#Override
public boolean matchesSafely(View view) {
ListView listView = (ListView) view;
counts[0] = listView.getCount();
return true;
}
#Override
public void describeTo(Description description) {
}
}));
2. Then, knowing the number of elements in listView you can scroll to any element within the range.
onData(anything()).inAdapterView(R.id.some_list_view).getPosition(<item_index>).perform(scrollTo())
If you already have this specific number then you have do something like this:
onData(is(instanceOf(yourClass.class)))
.inAdapterView(withId(R.id.some_list_view))
.atPosition(spicificNumber)
.perform(scrollTo());
This will fail if ListView doesn't have an item at position with specificNumber.
EDITED:
Take a look also at this example - Espresso samples. It will help you to check if there are no more items in the list after spesificNumber.
I am adding accessibility to an app and I am using google's talkback for testing accessibility and I am unable to block certain views from being selected.
Besides removing all listeners and focusability, is there any better way to disable views from obtaining focus when they are hidden on the screen... ie having a "drawer" open and disabling the selection of items in the content container? It seems like there should be a cleaner solution to this or maybe a fix is required on the talkback team's side.
Thanks
Look into AccessibilityDelegateCompat available in support-v4 library - Link.
Create an instance of AccessibilityDelegateCompat and override the following method:
#Override
public void onInitializeAccessibilityNodeInfo(View host,
AccessibilityNodeInfoCompat info) {
// Check if 'host' is visible or not before calling the super method
if (host.getVisibility() != View.INVISIBLE) {
super.onInitializeAccessibilityNodeInfo(host, info);
}
}
Finally, use static method ViewCompat.setAccessibilityDelegate(View, AccessibilityDelegateCompat) for the views that are invisible.
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.