{"record":{"id":"7a40a0c2da094dcb","repo":"yuliskov/SmartTube","slug":"cannot-settlecapturedviewat-outside-of-a-call-to-c","errorCode":null,"errorMessage":"Cannot settleCapturedViewAt outside of a call to Callback#onViewReleased","messagePattern":"Cannot settleCapturedViewAt outside of a call to Callback#onViewReleased","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"slidableactivity/src/main/java/com/r0adkll/slidr/util/ViewDragHelper.java","lineNumber":526,"sourceCode":"            mCapturedView = null;\n        }\n        return continueSliding;\n    }\n\n    /**\n     * Settle the captured view at the given (left, top) position.\n     * The appropriate velocity from prior motion will be taken into account.\n     * If this method returns true, the caller should invoke {@link #continueSettling(boolean)}\n     * on each subsequent frame to continue the motion until it returns false. If this method\n     * returns false there is no further work to do to complete the movement.\n     *\n     * @param finalLeft Settled left edge position for the captured view\n     * @param finalTop  Settled top edge position for the captured view\n     * @return true if animation should continue through {@link #continueSettling(boolean)} calls\n     */\n    public boolean settleCapturedViewAt(int finalLeft, int finalTop) {\n        if (!mReleaseInProgress) {\n            throw new IllegalStateException(\"Cannot settleCapturedViewAt outside of a call to \" +\n                    \"Callback#onViewReleased\");\n        }\n        return forceSettleCapturedViewAt(finalLeft, finalTop,\n                (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),\n                (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId));\n    }\n\n    /**\n     * Settle the captured view at the given (left, top) position.\n     *\n     * @param finalLeft Target left position for the captured view\n     * @param finalTop  Target top position for the captured view\n     * @param xvel      Horizontal velocity\n     * @param yvel      Vertical velocity\n     * @return true if animation should continue through {@link #continueSettling(boolean)} calls\n     */\n    private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) {\n        final int startLeft = mCapturedView.getLeft();","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/yuliskov/SmartTube/blob/3de8d90593e0166f012ca18cc3c7ba45bfd68ac4/slidableactivity/src/main/java/com/r0adkll/slidr/util/ViewDragHelper.java#L508-L544","documentation":"settleCapturedViewAt() animates the currently captured view to its resting position using the release velocity tracked by the helper. ViewDragHelper sets mReleaseInProgress only while dispatching Callback#onViewReleased; calling settle outside that window means there is no captured view/velocity to settle, so it throws IllegalStateException.","triggerScenarios":"Invoking settleCapturedViewAt(...) from a click handler, menu item, animation tick, or any code path other than inside your ViewDragHelper.Callback's onViewReleased(releasedChild, xvel, yvel) override.","commonSituations":"Adding a 'close' button that tries to snap the sliding panel shut; porting Scroller-based snap logic and reusing the same call; sharing one method between user-release and programmatic resets.","solutions":["Move the settleCapturedViewAt call inside Callback#onViewReleased — that is the only sanctioned window.","For programmatic moves outside a release, use smoothSlideViewTo(child, finalLeft, finalTop) (no such gate) and drive it with continueSettling(true) each frame.","Keep a reference to the draggable child so smoothSlideViewTo can target it when no view is captured."],"exampleFix":"// before — outside any release\n closeButton.setOnClickListener(v ->\n     mDragHelper.settleCapturedViewAt(getWidth(), getTop())); // throws IllegalStateException\n\n// after — programmatic move uses smoothSlideViewTo\n closeButton.setOnClickListener(v -> {\n     mDragHelper.smoothSlideViewTo(mDraggableChild, getWidth(), mDraggableChild.getTop());\n     ViewCompat.postInvalidateOnAnimation(mParentView);\n });\n\n // settle stays inside the release callback only\n @Override public void onViewReleased(View child, float xvel, float yvel) {\n     mDragHelper.settleCapturedViewAt(targetLeft(child, xvel), child.getTop());\n     ViewCompat.postInvalidateOnAnimation(mParentView);\n }","handlingStrategy":"validation","validationCode":"// legal window only: inside Callback#onViewReleased\n@Override\npublic void onViewReleased(View releasedChild, float xvel, float yvel) {\n    if (mDragHelper.getCapturedView() != null) {\n        mDragHelper.settleCapturedViewAt(targetLeft(releasedChild, xvel), releasedChild.getTop());\n        ViewCompat.postInvalidateOnAnimation(mParentView);\n    }\n}\n\n// everywhere else, use the ungated API:\nboolean ok = mDragHelper.smoothSlideViewTo(child, finalLeft, finalTop);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["settleCapturedViewAt only inside onViewReleased — treat it as part of the release contract.","Programmatic moves use smoothSlideViewTo + continueSettling(true) each frame.","Keep a field with the draggable child so you never need settle outside a release."],"tags":["android","view","drag","state-machine","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"3de8d90593e0166f012ca18cc3c7ba45bfd68ac4","analyzedAt":"2026-08-22T09:19:26.383Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}