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

Only one SwipeableListItem view is allowed in a ListItemLayo

Error message

Only one SwipeableListItem view is allowed in a ListItemLayout.

What it means

ListItemLayout designates the first SwipeableListItem child as its swipeable content view (contentView). If another SwipeableListItem is added while contentView is already set, the layout cannot know which view to translate during swipes, so addView throws UnsupportedOperationException.

Source

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

      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) {
      contentView = child;
    }
  }

  @Override
  public void onViewRemoved(View child) {
    super.onViewRemoved(child);
    if (child == swipeToRevealLayoutLeft) {
      swipeToRevealLayoutLeft = null;
    } else if (child == swipeToRevealLayoutRight) {
      swipeToRevealLayoutRight = null;
    } else if (contentView == child) {
      contentView = null;
    }

    if (!swipeToRevealLayoutExists() || contentView == null) {

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Keep exactly one SwipeableListItem per ListItemLayout — it should be the main content view.
  2. Ensure custom content views implement SwipeableListItem only once at the top level; nested helpers should not implement the interface.
  3. When swapping content dynamically, remove the old content view before adding the new one.

Example fix

<!-- before -->
<ListItemLayout>
  <SwipeableContentA .../>
  <SwipeableContentB .../> <!-- throws: second SwipeableListItem -->
</ListItemLayout>

<!-- after: one swipeable content; second area is a plain view inside it -->
<ListItemLayout>
  <SwipeableContent>
    <PlainHeaderView .../><PlainBodyView .../>
  </SwipeableContent>
  <RevealItem layout_gravity="end" .../>
</ListItemLayout>
Defensive patterns

Strategy: validation

Validate before calling

View oldContent = listItemLayout.findViewById(R.id.swipeable_content);
if (oldContent != null) listItemLayout.removeView(oldContent);
listItemLayout.addView(newSwipeableContent);

Prevention

When it happens

Trigger: Two views implementing SwipeableListItem in the same ListItemLayout (e.g. a custom content view plus a nested swipeable container); adding a second content view dynamically after the first bound one.

Common situations: Wrapping content in an extra swipeable container 'to be safe'; refactoring that nests SwipeableListItem implementations; third-party custom views implementing the interface unintentionally.

Related errors


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