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

No RevealableListItem with gravity {}

Error message

No RevealableListItem with gravity {}

What it means

getOffsetForSwipeState(swipeState, revealGravity) first requires that a RevealableListItem exists for the requested reveal gravity (start or end). It is an internal calculation for where the content view should sit; calling it for a gravity that has no reveal layout has no meaningful offset, so it throws IllegalArgumentException echoing the missing gravity value.

Source

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

    return getLayoutDirection() == LAYOUT_DIRECTION_RTL ? Gravity.LEFT : Gravity.RIGHT;
  }

  private boolean swipeToRevealLayoutExistsForGravity(@RevealGravity int gravity) {
    // Make sure the reveal layouts are associated with the correct gravities, in case there are any
    // swaps.
    maybeSwapRevealLayoutsForGravity();

    if (isRevealGravityLeft(gravity)) {
      return swipeToRevealLayoutLeft instanceof RevealableListItem;
    } else {
      return swipeToRevealLayoutRight instanceof RevealableListItem;
    }
  }

  private int getOffsetForSwipeState(
      @StableSwipeState int swipeState, @RevealGravity int revealGravity) {
    if (!swipeToRevealLayoutExistsForGravity(revealGravity)) {
      throw new IllegalArgumentException("No RevealableListItem with gravity " + revealGravity);
    }
    switch (swipeState) {
      case STATE_CLOSED:
        return getSwipeViewClosedOffset();
      case STATE_OPEN:
        return getSwipeRevealViewRevealedOffset(revealGravity);
      case STATE_SWIPE_PRIMARY_ACTION:
        return getSwipeToActionOffset(revealGravity);
      default:
        throw new IllegalArgumentException("Invalid state to get swipe offset: " + swipeState);
    }
  }

  private void updateSwipeProgress(int left) {
    if (!(contentView instanceof SwipeableListItem && swipeToRevealLayoutExists())) {
      return;
    }
    revealViewOffset = left - originalContentViewLeft;

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Before requesting a state for a gravity, add a RevealableListItem child with that gravity (start and/or end) to the ListItemLayout.
  2. If only one reveal side exists, always pass that side's gravity to setSwipeState.
  3. In RTL-aware code, resolve gravity from the reveal view's LayoutParams rather than a hardcoded constant.

Example fix

// before
listItemLayout.setSwipeState(
    ListItemLayout.STATE_OPEN, REVEAL_GRAVITY_START, true);
// layout only defines an end-gravity reveal -> throws

// after
int gravity = ((ListItemLayout.LayoutParams) revealView.getLayoutParams()).gravity;
listItemLayout.setSwipeState(ListItemLayout.STATE_OPEN, gravity, true);
Defensive patterns

Strategy: validation

Validate before calling

boolean startExists = listItemLayout.findViewById(R.id.reveal_start) != null;
boolean endExists = listItemLayout.findViewById(R.id.reveal_end) != null;
int gravity = startExists ? ListItemLayout.REVEAL_GRAVITY_START : ListItemLayout.REVEAL_GRAVITY_END;
if (!startExists && !endExists) throw new IllegalStateException("No reveal children defined");

Prevention

When it happens

Trigger: setSwipeState(STATE_OPEN/STATE_SWIPE_PRIMARY_ACTION, REVEAL_GRAVITY_START, ...) on a ListItemLayout that only has an end-gravity RevealableListItem; computing offsets via reflection or subclass code with a gravity the layout does not provide.

Common situations: Supporting both swipe directions in code while the XML only defines a reveal view on one side; RTL layouts where the expected gravity constant differs from what the layout actually holds.

Related errors


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