{"record":{"id":"1c5f9ce48a8216a2","repo":"yuliskov/SmartTube","slug":"cannot-flingcapturedview-outside-of-a-call-to-call","errorCode":null,"errorMessage":"Cannot flingCapturedView outside of a call to Callback#onViewReleased","messagePattern":"Cannot flingCapturedView 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":650,"sourceCode":"    private float distanceInfluenceForSnapDuration(float f) {\n        f -= 0.5f; // center the values about 0.\n        f *= 0.3f * Math.PI / 2.0f;\n        return (float) Math.sin(f);\n    }\n\n    /**\n     * Settle the captured view based on standard free-moving fling behavior.\n     * The caller should invoke {@link #continueSettling(boolean)} on each subsequent frame\n     * to continue the motion until it returns false.\n     *\n     * @param minLeft Minimum X position for the view's left edge\n     * @param minTop  Minimum Y position for the view's top edge\n     * @param maxLeft Maximum X position for the view's left edge\n     * @param maxTop  Maximum Y position for the view's top edge\n     */\n    public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) {\n        if (!mReleaseInProgress) {\n            throw new IllegalStateException(\"Cannot flingCapturedView outside of a call to \" +\n                    \"Callback#onViewReleased\");\n        }\n        mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(),\n                (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),\n                (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),\n                minLeft, maxLeft, minTop, maxTop);\n        setDragState(STATE_SETTLING);\n    }\n\n    /**\n     * Move the captured settling view by the appropriate amount for the current time.\n     * If <code>continueSettling</code> returns true, the caller should call it again\n     * on the next frame to continue.\n     *\n     * @param deferCallbacks true if state callbacks should be deferred via posted message.\n     *                       Set this to true if you are calling this method from\n     *                       {@link android.view.View#computeScroll()} or similar methods\n     *                       invoked as part of layout or drawing.","sourceCodeStart":632,"sourceCodeEnd":668,"githubUrl":"https://github.com/yuliskov/SmartTube/blob/3de8d90593e0166f012ca18cc3c7ba45bfd68ac4/slidableactivity/src/main/java/com/r0adkll/slidr/util/ViewDragHelper.java#L632-L668","documentation":"flingCapturedView() applies a velocity-based fling to the currently captured view using the velocities the helper measured during the drag. Like settleCapturedViewAt, it is only legal while mReleaseInProgress is true — i.e., inside Callback#onViewReleased — and throws IllegalStateException anywhere else.","triggerScenarios":"Calling flingCapturedView(...) from any code other than the onViewReleased override: dismiss buttons, timers, chained animations, or helper classes that trigger flings on their own schedule.","commonSituations":"Implementing slide-to-dismiss with an extra programmatic dismiss trigger; refactoring release logic into a separate class that calls fling directly; mimicking bottom-sheet behavior outside the release callback.","solutions":["Move flingCapturedView into Callback#onViewReleased, computing min/max bounds there.","For programmatic dismissal outside a release, use smoothSlideViewTo(child, finalLeft, finalTop) plus continueSettling(true) per frame instead.","If you need fling physics outside a release, compute the target yourself and settle with smoothSlideViewTo."],"exampleFix":"// before\nvoid dismissProgrammatically() {\n    mDragHelper.flingCapturedView(0, 0, getWidth(), getHeight()); // throws outside release\n}\n\n// after\nvoid dismissProgrammatically() {\n    mDragHelper.smoothSlideViewTo(mDraggableChild, mParentView.getWidth(), mDraggableChild.getTop());\n    ViewCompat.postInvalidateOnAnimation(mParentView);\n}\n\n@Override public void onViewReleased(View child, float xvel, float yvel) {\n    mDragHelper.flingCapturedView(0, 0, mParentView.getWidth(), mParentView.getHeight());\n    ViewCompat.postInvalidateOnAnimation(mParentView);\n}","handlingStrategy":"validation","validationCode":"// fling is legal only inside onViewReleased\n@Override\npublic void onViewReleased(View child, float xvel, float yvel) {\n    mDragHelper.flingCapturedView(0, 0, mParentView.getWidth(), mParentView.getHeight());\n    ViewCompat.postInvalidateOnAnimation(mParentView);\n}\n\n// programmatic dismiss path (outside release):\nmDragHelper.smoothSlideViewTo(child, mParentView.getWidth(), child.getTop());\nViewCompat.postInvalidateOnAnimation(mParentView);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["flingCapturedView and settleCapturedViewAt share the same release-window rule.","Route dismiss/close buttons through smoothSlideViewTo, not fling/settle.","Re-check any ported Scroller code for calls made outside onViewReleased."],"tags":["android","view","drag","state-machine","fling"],"backgroundTag":"invalid-state-transition","analyzedSha":"3de8d90593e0166f012ca18cc3c7ba45bfd68ac4","analyzedAt":"2026-08-22T09:19:26.383Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}