{"record":{"id":"762783393976acff","repo":"yuliskov/SmartTube","slug":"capturechildview-parameter-must-be-a-descendant-o","errorCode":null,"errorMessage":"captureChildView: parameter must be a descendant of the ViewDragHelper's tracked parent view (${mParentView})","messagePattern":"captureChildView: parameter must be a descendant of the ViewDragHelper's tracked parent view \\((.+?)\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"slidableactivity/src/main/java/com/r0adkll/slidr/util/ViewDragHelper.java","lineNumber":426,"sourceCode":"     *\n     * @return The size of an edge in pixels\n     * @see #setEdgeTrackingEnabled(int)\n     */\n    public int getEdgeSize() {\n        return mEdgeSize;\n    }\n\n    /**\n     * Capture a specific child view for dragging within the parent. The callback will be notified\n     * but {@link Callback#tryCaptureView(android.view.View, int)} will not be asked permission to\n     * capture this view.\n     *\n     * @param childView       Child view to capture\n     * @param activePointerId ID of the pointer that is dragging the captured child view\n     */\n    public void captureChildView(View childView, int activePointerId) {\n        if (childView.getParent() != mParentView) {\n            throw new IllegalArgumentException(\"captureChildView: parameter must be a descendant \" +\n                    \"of the ViewDragHelper's tracked parent view (\" + mParentView + \")\");\n        }\n        mCapturedView = childView;\n        mActivePointerId = activePointerId;\n        mCallback.onViewCaptured(childView, activePointerId);\n        setDragState(STATE_DRAGGING);\n    }\n\n    /**\n     * @return The currently captured view, or null if no view has been captured.\n     */\n    public View getCapturedView() {\n        return mCapturedView;\n    }\n\n    /**\n     * @return The ID of the pointer currently dragging the captured view,\n     * or {@link #INVALID_POINTER}.","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/yuliskov/SmartTube/blob/3de8d90593e0166f012ca18cc3c7ba45bfd68ac4/slidableactivity/src/main/java/com/r0adkll/slidr/util/ViewDragHelper.java#L408-L444","documentation":"captureChildView(view, pointerId) forcibly starts dragging a view without asking Callback#tryCaptureView. ViewDragHelper tracks exactly one parent ViewGroup, and the target's immediate parent (childView.getParent()) must be that exact view, otherwise IllegalArgumentException. Note getParent() returns the direct parent, so grandchildren of the tracked container fail the check too.","triggerScenarios":"Passing a nested descendant (e.g., a label two levels inside a card row) instead of a direct child of the ViewGroup given to ViewDragHelper.create(); passing a view from another hierarchy or a view not yet attached (getParent() is null).","commonSituations":"Custom leanback/card layouts where the touch target sits deeper than the tracked container; creating the helper on the window decor but capturing an inner panel; RecyclerView children whose parent is the RecyclerView while the helper tracks its parent; view recycling swapping parents between checks.","solutions":["Create the ViewDragHelper on the immediate parent of the view you intend to capture.","Capture the direct child and let the callback decide how nested content moves, rather than capturing a grandchild.","Guard the call: if (child.getParent() == trackedParent) helper.captureChildView(child, pointerId).","When the target really is nested, capture its ancestor that is a direct child and translate motion in your callback."],"exampleFix":"// before\nmHelper.captureChildView(rowLabel, pointerId); // rowLabel is a grandchild → throws\n\n// after — capture the direct child of the tracked parent\nView directChild = (View) rowLabel.getParent(); // card row, direct child of tracked ViewGroup\nif (directChild.getParent() == mParentTrackedByHelper) {\n    mHelper.captureChildView(directChild, pointerId);\n}","handlingStrategy":"validation","validationCode":"void captureIfDirectChild(View target, int pointerId) {\n    if (target != null && mParentTracked.equals(target.getParent())) {\n        mHelper.captureChildView(target, pointerId);\n    } else {\n        // walk up to the direct child of the tracked parent\n        View p = target;\n        while (p != null && !mParentTracked.equals(p.getParent())) {\n            p = (View) p.getParent();\n        }\n        if (p != null) mHelper.captureChildView(p, pointerId);\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Create ViewDragHelper on the immediate parent of the views you capture.","Remember getParent() is the DIRECT parent — grandchildren fail the check.","Check target.getParent() == trackedParent before every captureChildView call."],"tags":["android","view","view-hierarchy","drag"],"backgroundTag":"view-hierarchy-mismatch","analyzedSha":"3de8d90593e0166f012ca18cc3c7ba45bfd68ac4","analyzedAt":"2026-08-22T09:19:26.383Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}