Skip to content

5.x | Expandable items

Peter WONG edited this page Jul 25, 2018 · 21 revisions

In this page


Initialization

The Expandable item is introduced in Item Interfaces wiki page, while here instead, it's shown how to manage a list of expandable items for FlexibleAdapter.

ℹ️ Note: In order to expand/collapse an item, you must add a click listener to the Adapter or alternatively implement the click listener to a specific inner view of the item and call toggleExpansion() method in the ExpandableViewHolder as done in the overridden onClick.

The main list is composed only by expandable items, optionally the items can be expanded all together at startUp, but in order to see the subItems, the expanded flag must be initialized with true:

/*
 * List of Expandable items (headers/sections) with SubItems with Header attached.
 */
void init() {
    for (int i = 0; i < size; i++) {
       items.add(newExpandableSectionItem(i + 1)); //With expansion level 0
    }
    // stableIds=true because IDs are unique
    mAdapter = new FlexibleAdapter(items, listeners, true);
    // The next command must be coherent with the expanded flag at the creation phase!
    // So, if you have at least 1 item initially set as expanded you should call this.
    mAdapter.expandItemsAtStartUp();
}
/*
 * Creates a special expandable item which is also a Header.
 * The subItems will have linked its parent as Header!
 */
ExpandableHeaderItem newExpandableSectionItem(int i) {
    // The IDs are unique!
    ExpandableHeaderItem expandableItem = new ExpandableHeaderItem("EH" + i);
    expandableItem.setExpanded(true); //Or initialized in the constructor!
    expandableItem.setTitle("Expandable Header " + i);
    for (int j = 1; j <= 5; j++) {
        SubItem subItem = new SubItem(expandableItem.getId() + "-SB" + j);
        subItem.setTitle("Sub Item " + j);
        // OPTIONAL: In case you want to handle Headers or Sticky Headers:
        // The Header is the same parent, the expandable instance itself.
        subItem.setHeader(expandableItem);
        // Add the subItem to the parent
        expandableItem.addSubItem(subItem);
    }
    return expandableItem;
}

Initialization (Multi level)

Here it's a bit tricky. The level is declared in the item itself by overriding the method getExpansionLevel() in IExpandable implementation. Default value is 0 and each sub expandable item should return a level +1 for each sub level. The expandable may be seen as a folder containing others folders and files.

/*
 * List of Headers (level 0) with Expandable SubItems (level 1) with SubItems.
 */
void init() {
    for (int i = 0; i < size; i++) {
       items.add(newExpandableLevelItem(i + 1));
    }
    // stableIds=true because IDs are unique
    mAdapter = new FlexibleAdapter(items, listeners, true);
    // The next command must be coherent with the expanded flag at the creation phase!
    // So, if you have at least 1 item initially set as expanded you should call this.
    mAdapter.expandItemsAtStartUp();
}
/*
 * Creates a special expandable item which has another level of expandable.
 * IMPORTANT: Give unique IDs to each child and override getExpansionLevel()!
 */
ExpandableLevel0Item newExpandableLevelItem(int i) {
    // The IDs are unique!
    // ExpandableLevel0Item is an expandable with Level=0
    ExpandableLevel0Item expandableL0Item = new ExpandableLevel0Item("EI" + i);
    expandableL0Item.setExpanded(true); //Or initialized in the constructor!
    expandableL0Item.setTitle("Expandable Two-Levels " + i);
    for (int j = 1; j <= 5; j++) {
        // ExpandableLevel1Item is an expandable as well with Level=1
        ExpandableLevel1Item expandableL1Item = new ExpandableLevel1Item(
                expandableL0Item.getId() + "-EII" + j);
        expandableL1Item.setTitle("Sub Expandable " + j);
        for (int k = 1; k <= 3; k++) {
            // SubItem is not an expandable, so no level is specified!
            SubItem subItem = new SubItem(expandableL1Item.getId() + "-SB" + k);
            subItem.setTitle("Sub Sub Item " + k);
            expandableL1Item.addSubItem(subItem);
        }
        expandableL0Item.addSubItem(expandableL1Item);
    }
    return expandableL0Item;
}

Selection Coherence

This feature is always on.

  • When user selects a sub item of any level, it is not possible anymore to collapse the above parents until all children are deselected, it is however possible to expand and collapse others expandable.
  • You can only select items of the same type: first item selected makes the rule.

Expandable methods

Expand/Collapse commands

  • Map and expand items that are initially configured to be shown as expanded. This method should be called during the creation of the Activity/Fragment, useful also after a screen rotation.
expandItemsAtStartUp()
  • Expand an item that is of type IExpandable, not yet expanded and if has subItems.
    If configured, automatic smooth scroll will be performed when necessary.
expand(@IntRange(from = 0) int position)
expand(@IntRange(from = 0) int position, boolean notifyParent)
expand(T item)
expand(T item, boolean init) //Use carefully! Risk of duplicated items.
// Expands all IExpandable items with minimum of level
// "minCollapsibleLevel" previously set.
expandAll()
// Expands all IExpandable items with at least the specified level.
expandAll(int level)
  • Collapse an IExpandable item that is already expanded and if no subItem is selected. Multilevel option behaviors:
    • IExpandable subItems, that are expanded, can be recursively collapsed.
    • You can set the minimum level to auto-collapse siblings.
collapse(@IntRange(from = 0) int position)
collapse(@IntRange(from = 0) int position, boolean notifyParent)
// Collapses all expandable items with the minimum level of
// "minCollapsibleLevel" previously set.
collapseAll()
// Collapses all expandable items with the level equals-higher than
// the specified level.
collapseAll(int level)

Add subItem(s) commands

Use the following methods when a parent is already expanded. You are responsible to initially add the sub elements at correct position in the sub list of the expandable and then call those adapter methods as well.
In order to add subItems, the item resulting from the parent position must be of type IExpandable.

// 3 mandatory parameters and 2 optional
addSubItem(@IntRange(from = 0) int parentPosition,
           @IntRange(from = 0) int subPosition,
           @NonNull T item, //sub item to add
           [boolean expandParent, @Nullable Object payload])

addSubItems(@IntRange(from = 0) int parentPosition,
            @IntRange(from = 0) int subPosition,
            @NonNull List<T> items, //List of sub items to add
            [boolean expandParent, @Nullable Object payload])

ℹ️ Tip: When expandable is collapsed you can add/set elements to the expandable sub list and then call expand()! Check AbstractExpandableItem class, it has already utility methods for sub list.

Configuration methods

  • Automatically collapse all previous expanded parents before expand the new clicked parent. Default value is false (disabled). This parameter works in collaboration with setMinCollapsibleLevel().
isAutoCollapseOnExpand()
setAutoCollapseOnExpand(boolean collapseOnExpand)
  • Automatically scroll the clicked expandable item to the first visible position. Default value is false (disabled).

ℹ️ Note: This works ONLY in combination with SmoothScrollLinearLayoutManager or with SmoothScrollGridLayoutManager.

isAutoScrollOnExpand()
setAutoScrollOnExpand(boolean scrollOnExpand)
  • (Available from RC3 release) Automatically collapse all inner sub expandable when higher parent is collapsed. By keeping this parameter false, their expanded status remains expanded=true so when the higher parent is expanded again, the sub expandables will appear again expanded.
    Default value is false (keep expanded status). This parameter works in collaboration with setMinCollapsibleLevel().
isRecursiveCollapse()
setRecursiveCollapse(boolean collapseSubLevels)
  • Set the minimum level which all sub expandable items will be collapsed too. Default value is minCollapsibleLevel (All levels including 0). This parameter works in collaboration with setRecursiveCollapse().
getMinCollapsibleLevel()
setMinCollapsibleLevel(int minCollapsibleLevel)

Utility methods

isExpandable(@Nullable T item) //checks nullity as well
isExpanded(@Nullable T item) //checks also if item IExpandable!
isExpanded(@IntRange(from = 0) int position) //checks also if item is IExpandable!

// Retrieves the parent of a child.
getExpandableOf(@IntRange(from = 0) int position)
getExpandableOf(@NonNull T child)
// Retrieves the parent position of a child.
getExpandablePositionOf(@NonNull T child)

// Retrieves the expandable of the deleted child.
getExpandableOfDeletedChild(@NonNull T child)
// Retrieves only the deleted children of the specified parent.
getDeletedChildren(IExpandable expandable)
// Retrieves all the original children of the specified parent,
// filtering out all the deleted children if any.
getCurrentChildren(@Nullable IExpandable expandable)
hasSubItems(@NonNull IExpandable expandable) //checks nullity as well

// Retrieves the position of a child item in the list where it lays.
getSubPositionOf(@NonNull T child)
// Provides the full sub list where the child currently lays.
getSiblingsOf(@NonNull T child)
// Provides a list of all expandable items that are currently expanded.
getExpandedItems()
// Provides a list of all expandable positions that are currently expanded.
getExpandedPositions()

Selection coherence methods

isAnyChildSelected()
isAnyParentSelected()
Clone this wiki locally