{"record":{"id":"3b86a2c67131639f","repo":"material-components/material-components-android","slug":"listitemlayout-must-have-a-swipeablelistitem-child","errorCode":null,"errorMessage":"ListItemLayout must have a SwipeableListItem child and a RevealableListItem child to be swiped.","messagePattern":"ListItemLayout must have a SwipeableListItem child and a RevealableListItem child to be swiped\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lib/java/com/google/android/material/listitem/ListItemLayout.java","lineNumber":919,"sourceCode":"  }\n\n  /**\n   * Sets the state to swipe the {@link SwipeableListItem} child to.\n   *\n   * @param swipeState The state to swipe to. This must be one of {@link\n   *     SwipeableListItem#STATE_CLOSED}, {@link SwipeableListItem#STATE_OPEN}, or {@link\n   *     SwipeableListItem#STATE_SWIPE_PRIMARY_ACTION}\n   * @param revealGravity The gravity of the {@link RevealableListItem} to reveal when swiping.\n   * @param animate Whether to animate to the given swipe state.\n   */\n  public void setSwipeState(\n      @StableSwipeState int swipeState, @RevealGravity int revealGravity, boolean animate) {\n    if (swipeState != STATE_CLOSED\n        && swipeState != STATE_OPEN\n        && swipeState != STATE_SWIPE_PRIMARY_ACTION) {\n      throw new IllegalArgumentException(\"Invalid swipe state: \" + swipeState);\n    } else if (!(contentView instanceof SwipeableListItem) || !swipeToRevealLayoutExists()) {\n      throw new IllegalArgumentException(\n          \"ListItemLayout must have a SwipeableListItem child and a RevealableListItem child to be\"\n              + \" swiped.\");\n    } else if (swipeState != STATE_CLOSED && !swipeToRevealLayoutExistsForGravity(revealGravity)) {\n      throw new IllegalArgumentException(\n          \"No RevealableListItem is defined for the given gravity: \" + revealGravity);\n    }\n\n    Runnable runnable =\n        () -> {\n          if (!animate) {\n            if (viewDragHelper != null) {\n              viewDragHelper.abort();\n            }\n            int finalLeft = getOffsetForSwipeState(swipeState, revealGravity);\n            contentView.offsetLeftAndRight(finalLeft - contentView.getLeft());\n            updateSwipeProgress(finalLeft);\n            setSwipeStateInternal(swipeState, revealGravity);\n          } else {","sourceCodeStart":901,"sourceCodeEnd":937,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/listitem/ListItemLayout.java#L901-L937","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the ListItemLayout XML (or dynamic construction) always includes one SwipeableListItem and at least one RevealableListItem before calling setSwipeState.","Delay state restoration until after bind/layout: use itemView.post { ... } or do it in onBindViewHolder once children exist.","To hide a reveal view temporarily, set visibility=GONE instead of removing it from the layout."],"exampleFix":"// before\ninit { listItemLayout.setSwipeState(STATE_OPEN, gravity, false) } // children not inflated yet\n\n// after\nlistItemLayout.post {\n  listItemLayout.setSwipeState(STATE_OPEN, gravity, false); // children attached\n};","handlingStrategy":"validation","validationCode":"boolean hasContent = listItemLayout.findViewById(R.id.swipeable_content) != null;\nboolean hasReveal = listItemLayout.findViewById(R.id.reveal_end) != null\n    || listItemLayout.findViewById(R.id.reveal_start) != null;\nif (hasContent && hasReveal) listItemLayout.setSwipeState(state, gravity, animate);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restore swipe state after inflation/bind (itemView.post or onBindViewHolder), never in constructors.","Hide reveal children with GONE rather than removing them.","Structure item layouts to always contain the required children."],"tags":["material-components","listitem","swipe","lifecycle"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}