material-components/material-components-android · error · IllegalArgumentException

ListItemLayout must have a SwipeableListItem child and a Rev

Error message

ListItemLayout must have a SwipeableListItem child and a RevealableListItem child to be swiped.

What it means

setSwipeState requires the ListItemLayout to be structurally complete before it can animate swipes: it must contain a SwipeableListItem content child (contentView) and at least one RevealableListItem. If either is missing there is nothing to swipe or reveal, so the method throws IllegalArgumentException telling you which children are required.

Source

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

  }

  /**
   * Sets the state to swipe the {@link SwipeableListItem} child to.
   *
   * @param swipeState The state to swipe to. This must be one of {@link
   *     SwipeableListItem#STATE_CLOSED}, {@link SwipeableListItem#STATE_OPEN}, or {@link
   *     SwipeableListItem#STATE_SWIPE_PRIMARY_ACTION}
   * @param revealGravity The gravity of the {@link RevealableListItem} to reveal when swiping.
   * @param animate Whether to animate to the given swipe state.
   */
  public void setSwipeState(
      @StableSwipeState int swipeState, @RevealGravity int revealGravity, boolean animate) {
    if (swipeState != STATE_CLOSED
        && swipeState != STATE_OPEN
        && swipeState != STATE_SWIPE_PRIMARY_ACTION) {
      throw new IllegalArgumentException("Invalid swipe state: " + swipeState);
    } else if (!(contentView instanceof SwipeableListItem) || !swipeToRevealLayoutExists()) {
      throw new IllegalArgumentException(
          "ListItemLayout must have a SwipeableListItem child and a RevealableListItem child to be"
              + " swiped.");
    } else if (swipeState != STATE_CLOSED && !swipeToRevealLayoutExistsForGravity(revealGravity)) {
      throw new IllegalArgumentException(
          "No RevealableListItem is defined for the given gravity: " + revealGravity);
    }

    Runnable runnable =
        () -> {
          if (!animate) {
            if (viewDragHelper != null) {
              viewDragHelper.abort();
            }
            int finalLeft = getOffsetForSwipeState(swipeState, revealGravity);
            contentView.offsetLeftAndRight(finalLeft - contentView.getLeft());
            updateSwipeProgress(finalLeft);
            setSwipeStateInternal(swipeState, revealGravity);
          } else {

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Ensure the ListItemLayout XML (or dynamic construction) always includes one SwipeableListItem and at least one RevealableListItem before calling setSwipeState.
  2. Delay state restoration until after bind/layout: use itemView.post { ... } or do it in onBindViewHolder once children exist.
  3. To hide a reveal view temporarily, set visibility=GONE instead of removing it from the layout.

Example fix

// before
init { listItemLayout.setSwipeState(STATE_OPEN, gravity, false) } // children not inflated yet

// after
listItemLayout.post {
  listItemLayout.setSwipeState(STATE_OPEN, gravity, false); // children attached
};
Defensive patterns

Strategy: validation

Validate before calling

boolean hasContent = listItemLayout.findViewById(R.id.swipeable_content) != null;
boolean hasReveal = listItemLayout.findViewById(R.id.reveal_end) != null
    || listItemLayout.findViewById(R.id.reveal_start) != null;
if (hasContent && hasReveal) listItemLayout.setSwipeState(state, gravity, animate);

Prevention

When it happens

Trigger: Calling setSwipeState before the layout is inflated with its children (e.g. in the constructor of a custom view or too early in a fragment lifecycle); a layout XML missing the reveal container; children removed dynamically leaving the layout incomplete.

Common situations: Restoring a saved swipe state in onViewStateRestored before the RecyclerView binds; conditionally hiding the reveal view via removeView instead of GONE; partial layouts during preview/edit-time inflation.

Related errors


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