Fields Summary |
---|
public static final int | PACKED_POSITION_TYPE_GROUPThe packed position represents a group. |
public static final int | PACKED_POSITION_TYPE_CHILDThe packed position represents a child. |
public static final int | PACKED_POSITION_TYPE_NULLThe packed position represents a neither/null/no preference. |
public static final long | PACKED_POSITION_VALUE_NULLThe value for a packed position that represents neither/null/no
preference. This value is not otherwise possible since a group type
(first bit 0) should not have a child position filled. |
private static final long | PACKED_POSITION_MASK_CHILDThe mask (in packed position representation) for the child |
private static final long | PACKED_POSITION_MASK_GROUPThe mask (in packed position representation) for the group |
private static final long | PACKED_POSITION_MASK_TYPEThe mask (in packed position representation) for the type |
private static final long | PACKED_POSITION_SHIFT_GROUPThe shift amount (in packed position representation) for the group |
private static final long | PACKED_POSITION_SHIFT_TYPEThe shift amount (in packed position representation) for the type |
private static final long | PACKED_POSITION_INT_MASK_CHILDThe mask (in integer child position representation) for the child |
private static final long | PACKED_POSITION_INT_MASK_GROUPThe mask (in integer group position representation) for the group |
private ExpandableListConnector | mConnectorServes as the glue/translator between a ListView and an ExpandableListView |
private ExpandableListAdapter | mAdapterGives us Views through group+child positions |
private int | mIndicatorLeftLeft bound for drawing the indicator. |
private int | mIndicatorRightRight bound for drawing the indicator. |
private int | mChildIndicatorLeftLeft bound for drawing the indicator of a child. Value of
{@link #CHILD_INDICATOR_INHERIT} means use mIndicatorLeft. |
private int | mChildIndicatorRightRight bound for drawing the indicator of a child. Value of
{@link #CHILD_INDICATOR_INHERIT} means use mIndicatorRight. |
public static final int | CHILD_INDICATOR_INHERITDenotes when a child indicator should inherit this bound from the generic
indicator bounds |
private android.graphics.drawable.Drawable | mGroupIndicatorThe indicator drawn next to a group. |
private android.graphics.drawable.Drawable | mChildIndicatorThe indicator drawn next to a child. |
private static final int[] | EMPTY_STATE_SET |
private static final int[] | GROUP_EXPANDED_STATE_SETState indicating the group is expanded. |
private static final int[] | GROUP_EMPTY_STATE_SETState indicating the group is empty (has no children). |
private static final int[] | GROUP_EXPANDED_EMPTY_STATE_SETState indicating the group is expanded and empty (has no children). |
private static final int[] | GROUP_STATE_SETSStates for the group where the 0th bit is expanded and 1st bit is empty. |
private static final int[] | CHILD_LAST_STATE_SETState indicating the child is the last within its group. |
private android.graphics.drawable.Drawable | mChildDividerDrawable to be used as a divider when it is adjacent to any children |
private boolean | mClipChildDivider |
private final android.graphics.Rect | mIndicatorRect |
private OnGroupCollapseListener | mOnGroupCollapseListener |
private OnGroupExpandListener | mOnGroupExpandListener |
private OnGroupClickListener | mOnGroupClickListener |
private OnChildClickListener | mOnChildClickListener |
Methods Summary |
---|
public boolean | collapseGroup(int groupPos)Collapse a group in the grouped list view
boolean retValue = mConnector.collapseGroup(groupPos);
if (mOnGroupCollapseListener != null) {
mOnGroupCollapseListener.onGroupCollapse(groupPos);
}
return retValue;
|
android.view.ContextMenu.ContextMenuInfo | createContextMenuInfo(android.view.View view, int flatListPosition, long id)
PositionMetadata pm = mConnector.getUnflattenedPos(flatListPosition);
ExpandableListPosition pos = pm.position;
pm.recycle();
id = getChildOrGroupId(pos);
long packedPosition = pos.getPackedPosition();
pos.recycle();
return new ExpandableListContextMenuInfo(view, packedPosition, id);
|
protected void | dispatchDraw(android.graphics.Canvas canvas)
// Draw children, etc.
super.dispatchDraw(canvas);
// If we have any indicators to draw, we do it here
if ((mChildIndicator == null) && (mGroupIndicator == null)) {
return;
}
int saveCount = 0;
final boolean clipToPadding = (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
if (clipToPadding) {
saveCount = canvas.save();
final int scrollX = mScrollX;
final int scrollY = mScrollY;
canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop,
scrollX + mRight - mLeft - mPaddingRight,
scrollY + mBottom - mTop - mPaddingBottom);
}
final int headerViewsCount = getHeaderViewsCount();
final int lastChildFlPos = mItemCount - getFooterViewsCount() - headerViewsCount - 1;
final int myB = mBottom;
PositionMetadata pos;
View item;
Drawable indicator;
int t, b;
// Start at a value that is neither child nor group
int lastItemType = ~(ExpandableListPosition.CHILD | ExpandableListPosition.GROUP);
final Rect indicatorRect = mIndicatorRect;
// The "child" mentioned in the following two lines is this
// View's child, not referring to an expandable list's
// notion of a child (as opposed to a group)
final int childCount = getChildCount();
for (int i = 0, childFlPos = mFirstPosition - headerViewsCount; i < childCount;
i++, childFlPos++) {
if (childFlPos < 0) {
// This child is header
continue;
} else if (childFlPos > lastChildFlPos) {
// This child is footer, so are all subsequent children
break;
}
item = getChildAt(i);
t = item.getTop();
b = item.getBottom();
// This item isn't on the screen
if ((b < 0) || (t > myB)) continue;
// Get more expandable list-related info for this item
pos = mConnector.getUnflattenedPos(childFlPos);
// If this item type and the previous item type are different, then we need to change
// the left & right bounds
if (pos.position.type != lastItemType) {
if (pos.position.type == ExpandableListPosition.CHILD) {
indicatorRect.left = (mChildIndicatorLeft == CHILD_INDICATOR_INHERIT) ?
mIndicatorLeft : mChildIndicatorLeft;
indicatorRect.right = (mChildIndicatorRight == CHILD_INDICATOR_INHERIT) ?
mIndicatorRight : mChildIndicatorRight;
} else {
indicatorRect.left = mIndicatorLeft;
indicatorRect.right = mIndicatorRight;
}
lastItemType = pos.position.type;
}
if (indicatorRect.left != indicatorRect.right) {
// Use item's full height + the divider height
if (mStackFromBottom) {
// See ListView#dispatchDraw
indicatorRect.top = t;// - mDividerHeight;
indicatorRect.bottom = b;
} else {
indicatorRect.top = t;
indicatorRect.bottom = b;// + mDividerHeight;
}
// Get the indicator (with its state set to the item's state)
indicator = getIndicator(pos);
if (indicator != null) {
// Draw the indicator
indicator.setBounds(indicatorRect);
indicator.draw(canvas);
}
}
pos.recycle();
}
if (clipToPadding) {
canvas.restoreToCount(saveCount);
}
|
void | drawDivider(android.graphics.Canvas canvas, android.graphics.Rect bounds, int childIndex)
int flatListPosition = childIndex + mFirstPosition;
// Only proceed as possible child if the divider isn't above all items (if it is above
// all items, then the item below it has to be a group)
if (flatListPosition >= 0) {
PositionMetadata pos = mConnector.getUnflattenedPos(flatListPosition);
// If this item is a child, or it is a non-empty group that is expanded
if ((pos.position.type == ExpandableListPosition.CHILD) || (pos.isExpanded() &&
pos.groupMetadata.lastChildFlPos != pos.groupMetadata.flPos)) {
// These are the cases where we draw the child divider
final Drawable divider = mChildDivider;
final boolean clip = mClipChildDivider;
if (!clip) {
divider.setBounds(bounds);
} else {
canvas.save();
canvas.clipRect(bounds);
}
divider.draw(canvas);
if (clip) {
canvas.restore();
}
pos.recycle();
return;
}
pos.recycle();
}
// Otherwise draw the default divider
super.drawDivider(canvas, bounds, flatListPosition);
|
public boolean | expandGroup(int groupPos)Expand a group in the grouped list view
boolean retValue = mConnector.expandGroup(groupPos);
if (mOnGroupExpandListener != null) {
mOnGroupExpandListener.onGroupExpand(groupPos);
}
return retValue;
|
public ListAdapter | getAdapter()This method should not be used, use {@link #getExpandableListAdapter()}.
/*
* The developer should never really call this method on an
* ExpandableListView, so it would be nice to throw a RuntimeException,
* but AdapterView calls this
*/
return super.getAdapter();
|
private long | getChildOrGroupId(ExpandableListPosition position)Gets the ID of the group or child at the given position .
This is useful since there is no ListAdapter ID -> ExpandableListAdapter
ID conversion mechanism (in some cases, it isn't possible).
if (position.type == ExpandableListPosition.CHILD) {
return mAdapter.getChildId(position.groupPos, position.childPos);
} else {
return mAdapter.getGroupId(position.groupPos);
}
|
public ExpandableListAdapter | getExpandableListAdapter()Gets the adapter that provides data to this view.
return mAdapter;
|
public long | getExpandableListPosition(int flatListPosition)Converts a flat list position (the raw position of an item (child or
group) in the list) to an group and/or child position (represented in a
packed position). This is useful in situations where the caller needs to
use the underlying {@link ListView}'s methods. Use
{@link ExpandableListView#getPackedPositionType} ,
{@link ExpandableListView#getPackedPositionChild},
{@link ExpandableListView#getPackedPositionGroup} to unpack.
PositionMetadata pm = mConnector.getUnflattenedPos(flatListPosition);
long packedPos = pm.position.getPackedPosition();
pm.recycle();
return packedPos;
|
public int | getFlatListPosition(long packedPosition)Converts a group and/or child position to a flat list position. This is
useful in situations where the caller needs to use the underlying
{@link ListView}'s methods.
PositionMetadata pm = mConnector.getFlattenedPos(ExpandableListPosition
.obtainPosition(packedPosition));
int retValue = pm.position.flatListPos;
pm.recycle();
return retValue;
|
private android.graphics.drawable.Drawable | getIndicator(android.widget.ExpandableListConnector.PositionMetadata pos)Gets the indicator for the item at the given position. If the indicator
is stateful, the state will be given to the indicator.
Drawable indicator;
if (pos.position.type == ExpandableListPosition.GROUP) {
indicator = mGroupIndicator;
if (indicator != null && indicator.isStateful()) {
// Empty check based on availability of data. If the groupMetadata isn't null,
// we do a check on it. Otherwise, the group is collapsed so we consider it
// empty for performance reasons.
boolean isEmpty = (pos.groupMetadata == null) ||
(pos.groupMetadata.lastChildFlPos == pos.groupMetadata.flPos);
final int stateSetIndex =
(pos.isExpanded() ? 1 : 0) | // Expanded?
(isEmpty ? 2 : 0); // Empty?
indicator.setState(GROUP_STATE_SETS[stateSetIndex]);
}
} else {
indicator = mChildIndicator;
if (indicator != null && indicator.isStateful()) {
// No need for a state sets array for the child since it only has two states
final int stateSet[] = pos.position.flatListPos == pos.groupMetadata.lastChildFlPos
? CHILD_LAST_STATE_SET
: EMPTY_STATE_SET;
indicator.setState(stateSet);
}
}
return indicator;
|
public static int | getPackedPositionChild(long packedPosition)Gets the child position from a packed position that is of
{@link #PACKED_POSITION_TYPE_CHILD} type (use {@link #getPackedPositionType(long)}).
To get the group that this child belongs to, use
{@link #getPackedPositionGroup(long)}. See
{@link #getPackedPositionForChild(int, int)}.
// Null
if (packedPosition == PACKED_POSITION_VALUE_NULL) return -1;
// Group since a group type clears this bit
if ((packedPosition & PACKED_POSITION_MASK_TYPE) != PACKED_POSITION_MASK_TYPE) return -1;
return (int) (packedPosition & PACKED_POSITION_MASK_CHILD);
|
public static long | getPackedPositionForChild(int groupPosition, int childPosition)Returns the packed position representation of a child's position.
In general, a packed position should be used in
situations where the position given to/returned from an
{@link ExpandableListAdapter} or {@link ExpandableListView} method can
either be a child or group. The two positions are packed into a single
long which can be unpacked using
{@link #getPackedPositionChild(long)},
{@link #getPackedPositionGroup(long)}, and
{@link #getPackedPositionType(long)}.
return (((long)PACKED_POSITION_TYPE_CHILD) << PACKED_POSITION_SHIFT_TYPE)
| ((((long)groupPosition) & PACKED_POSITION_INT_MASK_GROUP)
<< PACKED_POSITION_SHIFT_GROUP)
| (childPosition & PACKED_POSITION_INT_MASK_CHILD);
|
public static long | getPackedPositionForGroup(int groupPosition)Returns the packed position representation of a group's position. See
{@link #getPackedPositionForChild(int, int)}.
// No need to OR a type in because PACKED_POSITION_GROUP == 0
return ((((long)groupPosition) & PACKED_POSITION_INT_MASK_GROUP)
<< PACKED_POSITION_SHIFT_GROUP);
|
public static int | getPackedPositionGroup(long packedPosition)Gets the group position from a packed position. See
{@link #getPackedPositionForChild(int, int)}.
// Null
if (packedPosition == PACKED_POSITION_VALUE_NULL) return -1;
return (int) ((packedPosition & PACKED_POSITION_MASK_GROUP) >> PACKED_POSITION_SHIFT_GROUP);
|
public static int | getPackedPositionType(long packedPosition)Gets the type of a packed position. See
{@link #getPackedPositionForChild(int, int)}.
if (packedPosition == PACKED_POSITION_VALUE_NULL) {
return PACKED_POSITION_TYPE_NULL;
}
return (packedPosition & PACKED_POSITION_MASK_TYPE) == PACKED_POSITION_MASK_TYPE
? PACKED_POSITION_TYPE_CHILD
: PACKED_POSITION_TYPE_GROUP;
|
public long | getSelectedId()Gets the ID of the currently selected group or child. Can return -1 if no
selection.
long packedPos = getSelectedPosition();
if (packedPos == PACKED_POSITION_VALUE_NULL) return -1;
int groupPos = getPackedPositionGroup(packedPos);
if (getPackedPositionType(packedPos) == PACKED_POSITION_TYPE_GROUP) {
// It's a group
return mAdapter.getGroupId(groupPos);
} else {
// It's a child
return mAdapter.getChildId(groupPos, getPackedPositionChild(packedPos));
}
|
public long | getSelectedPosition()Gets the position of the currently selected group or child (along with
its type). Can return {@link #PACKED_POSITION_VALUE_NULL} if no selection.
final int selectedPos = getSelectedItemPosition();
if (selectedPos == -1) return PACKED_POSITION_VALUE_NULL;
return getExpandableListPosition(selectedPos);
|
boolean | handleItemClick(android.view.View v, int position, long id)This will either expand/collapse groups (if a group was clicked) or pass
on the click to the proper child (if a child was clicked)
final PositionMetadata posMetadata = mConnector.getUnflattenedPos(position);
id = getChildOrGroupId(posMetadata.position);
boolean returnValue;
if (posMetadata.position.type == ExpandableListPosition.GROUP) {
/* It's a group, so handle collapsing/expanding */
if (posMetadata.isExpanded()) {
/* Collapse it */
mConnector.collapseGroup(posMetadata);
playSoundEffect(SoundEffectConstants.CLICK);
if (mOnGroupCollapseListener != null) {
mOnGroupCollapseListener.onGroupCollapse(posMetadata.position.groupPos);
}
} else {
/* It's a group click, so pass on event */
if (mOnGroupClickListener != null) {
if (mOnGroupClickListener.onGroupClick(this, v,
posMetadata.position.groupPos, id)) {
posMetadata.recycle();
return true;
}
}
/* Expand it */
mConnector.expandGroup(posMetadata);
playSoundEffect(SoundEffectConstants.CLICK);
if (mOnGroupExpandListener != null) {
mOnGroupExpandListener.onGroupExpand(posMetadata.position.groupPos);
}
}
returnValue = true;
} else {
/* It's a child, so pass on event */
if (mOnChildClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
return mOnChildClickListener.onChildClick(this, v, posMetadata.position.groupPos,
posMetadata.position.childPos, id);
}
returnValue = false;
}
posMetadata.recycle();
return returnValue;
|
public boolean | isGroupExpanded(int groupPosition)Whether the given group is currently expanded.
return mConnector.isGroupExpanded(groupPosition);
|
public void | onRestoreInstanceState(android.os.Parcelable state)
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
if (mConnector != null && ss.expandedGroupMetadataList != null) {
mConnector.setExpandedGroupMetadataList(ss.expandedGroupMetadataList);
}
|
public android.os.Parcelable | onSaveInstanceState()
Parcelable superState = super.onSaveInstanceState();
return new SavedState(superState,
mConnector != null ? mConnector.getExpandedGroupMetadataList() : null);
|
public boolean | performItemClick(android.view.View v, int position, long id)
// Ignore clicks in header/footers
final int headerViewsCount = getHeaderViewsCount();
final int footerViewsStart = mItemCount - getFooterViewsCount();
if (position < headerViewsCount || position >= footerViewsStart) {
// Clicked on a header/footer, so ignore pass it on to super
return super.performItemClick(v, position, id);
}
// Internally handle the item click
return handleItemClick(v, position - headerViewsCount, id);
|
public void | setAdapter(ExpandableListAdapter adapter)Sets the adapter that provides data to this view.
// Set member variable
mAdapter = adapter;
if (adapter != null) {
// Create the connector
mConnector = new ExpandableListConnector(adapter);
} else {
mConnector = null;
}
// Link the ListView (superclass) to the expandable list data through the connector
super.setAdapter(mConnector);
|
public void | setAdapter(ListAdapter adapter)This overloaded method should not be used, instead use
{@link #setAdapter(ExpandableListAdapter)}.
{@inheritDoc}
throw new RuntimeException(
"For ExpandableListView, use setAdapter(ExpandableListAdapter) instead of " +
"setAdapter(ListAdapter)");
|
public void | setChildDivider(android.graphics.drawable.Drawable childDivider)Sets the drawable that will be drawn adjacent to every child in the list. This will
be drawn using the same height as the normal divider ({@link #setDivider(Drawable)}) or
if it does not have an intrinsic height, the height set by {@link #setDividerHeight(int)}.
mChildDivider = childDivider;
mClipChildDivider = childDivider != null && childDivider instanceof ColorDrawable;
|
public void | setChildIndicator(android.graphics.drawable.Drawable childIndicator)Sets the indicator to be drawn next to a child.
mChildIndicator = childIndicator;
|
public void | setChildIndicatorBounds(int left, int right)Sets the drawing bounds for the child indicator. For either, you can
specify {@link #CHILD_INDICATOR_INHERIT} to use inherit from the general
indicator's bounds.
mChildIndicatorLeft = left;
mChildIndicatorRight = right;
|
public void | setGroupIndicator(android.graphics.drawable.Drawable groupIndicator)Sets the indicator to be drawn next to a group.
mGroupIndicator = groupIndicator;
|
public void | setIndicatorBounds(int left, int right)Sets the drawing bounds for the indicators (at minimum, the group indicator
is affected by this; the child indicator is affected by this if the
child indicator bounds are set to inherit).
mIndicatorLeft = left;
mIndicatorRight = right;
|
public void | setOnChildClickListener(android.widget.ExpandableListView$OnChildClickListener onChildClickListener)
mOnChildClickListener = onChildClickListener;
|
public void | setOnGroupClickListener(android.widget.ExpandableListView$OnGroupClickListener onGroupClickListener)
mOnGroupClickListener = onGroupClickListener;
|
public void | setOnGroupCollapseListener(android.widget.ExpandableListView$OnGroupCollapseListener onGroupCollapseListener)
mOnGroupCollapseListener = onGroupCollapseListener;
|
public void | setOnGroupExpandListener(android.widget.ExpandableListView$OnGroupExpandListener onGroupExpandListener)
mOnGroupExpandListener = onGroupExpandListener;
|
public void | setOnItemClickListener(OnItemClickListener l)Register a callback to be invoked when an item has been clicked and the
caller prefers to receive a ListView-style position instead of a group
and/or child position. In most cases, the caller should use
{@link #setOnGroupClickListener} and/or {@link #setOnChildClickListener}.
{@inheritDoc}
super.setOnItemClickListener(l);
|
public boolean | setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup)Sets the selection to the specified child. If the child is in a collapsed
group, the group will only be expanded and child subsequently selected if
shouldExpandGroup is set to true, otherwise the method will return false.
ExpandableListPosition elChildPos = ExpandableListPosition.obtainChildPosition(
groupPosition, childPosition);
PositionMetadata flatChildPos = mConnector.getFlattenedPos(elChildPos);
if (flatChildPos == null) {
// The child's group isn't expanded
// Shouldn't expand the group, so return false for we didn't set the selection
if (!shouldExpandGroup) return false;
expandGroup(groupPosition);
flatChildPos = mConnector.getFlattenedPos(elChildPos);
// Sanity check
if (flatChildPos == null) {
throw new IllegalStateException("Could not find child");
}
}
super.setSelection(flatChildPos.position.flatListPos);
elChildPos.recycle();
flatChildPos.recycle();
return true;
|
public void | setSelectedGroup(int groupPosition)Sets the selection to the specified group.
ExpandableListPosition elGroupPos = ExpandableListPosition
.obtainGroupPosition(groupPosition);
PositionMetadata pm = mConnector.getFlattenedPos(elGroupPos);
elGroupPos.recycle();
super.setSelection(pm.position.flatListPos);
pm.recycle();
|