material-components/material-components-android · error · UnsupportedOperationException

Only one RevealableListItem with end gravity is supported.

Error message

Only one RevealableListItem with end gravity is supported.

What it means

ListItemLayout (swipe-to-reveal list item container) supports at most one RevealableListItem child aligned to the end (right gravity in LTR). addView tracks that child in swipeToRevealLayoutRight; when a second end-aligned RevealableListItem is added, the layout cannot disambiguate which view to reveal, so it throws UnsupportedOperationException.

Source

Thrown at lib/java/com/google/android/material/listitem/ListItemLayout.java:244

        positionState = FIRST_STATE_SET;
        break;
      case POSITION_LAST:
        positionState = LAST_STATE_SET;
        break;
      case POSITION_MIDDLE:
        positionState = MIDDLE_STATE_SET;
        break;
    }
    refreshDrawableState();
  }

  @Override
  public void addView(View child, int index, ViewGroup.LayoutParams params) {
    super.addView(child, index, params);
    if (child instanceof RevealableListItem) {
      if (isRightAligned(child)) {
        if (swipeToRevealLayoutRight != null) {
          throw new UnsupportedOperationException(
              "Only one RevealableListItem with end gravity is supported.");
        }
        swipeToRevealLayoutRight = child;
      } else {
        if (swipeToRevealLayoutLeft != null) {
          throw new UnsupportedOperationException(
              "Only one RevealableListItem with start gravity is supported.");
        }
        swipeToRevealLayoutLeft = child;
      }
      // Start the reveal view at a desired width of 0
      ((RevealableListItem) child).setRevealedWidth(0);
      // Make sure reveal view has lower elevation
      child.setElevation(getElevation() - 1);
    } else if (contentView != null && child instanceof SwipeableListItem) {
      throw new UnsupportedOperationException(
          "Only one SwipeableListItem view is allowed in a ListItemLayout.");
    } else if (child instanceof SwipeableListItem) {

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Keep exactly one end-gravity RevealableListItem per ListItemLayout; place multiple end actions inside that single reveal container (it can itself hold several buttons).
  2. If two reveal areas are truly needed, use start gravity for one and end gravity for the other.
  3. When adding reveal views dynamically, remove the existing one first: removeView(swipeToRevealLayoutRight) before addView.

Example fix

<!-- before: two end-gravity reveal children -->
<com.google.android.material.listitem.ListItemLayout ...>
  <RevealLayoutEnd1 layout_gravity="end" .../>
  <RevealLayoutEnd2 layout_gravity="end" .../> <!-- throws -->
</...>

<!-- after: single end reveal container holding both actions -->
<com.google.android.material.listitem.ListItemLayout ...>
  <RevealContainer layout_gravity="end">
    <Button .../><Button .../>
  </RevealContainer>
</...>
Defensive patterns

Strategy: validation

Validate before calling

int endReveals = 0;
for (int i = 0; i < listItemLayout.getChildCount(); i++) {
  View c = listItemLayout.getChildAt(i);
  if (c instanceof RevealableListItem && ViewCompat.getLayoutDirection(c) == LTR
      && isRightGravity(c)) endReveals++;
}
if (endReveals > 1) throw new IllegalStateException("Duplicate end reveal children in XML");

Prevention

When it happens

Trigger: Inflating or programmatically adding two views implementing RevealableListItem both with end/right gravity into one ListItemLayout; XML layouts with two reveal containers using layout_gravity="end".

Common situations: Design iterating toward two actions on one side; merging layouts by copy-paste leaving a duplicate reveal container; conditional UI code adding a reveal view without removing the previous one.

Related errors


AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14). Data as JSON: /api/errors/767c17a9237fed22. Report an issue: GitHub.