{"record":{"id":"0edf4ad557876f98","repo":"material-components/material-components-android","slug":"scroll-bar-must-contain-a-child-to-calculate-inter","errorCode":null,"errorMessage":"Scroll bar must contain a child to calculate interpolation.","messagePattern":"Scroll bar must contain a child to calculate interpolation\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"lib/java/com/google/android/material/shape/InterpolateOnScrollPositionChangeHelper.java","lineNumber":107,"sourceCode":"   * @param viewTreeObserver {@link ViewTreeObserver belonging to the {@link View} being\n   * interpolated.\n   */\n  public void stopListeningForScrollChanges(@NonNull ViewTreeObserver viewTreeObserver) {\n    viewTreeObserver.removeOnScrollChangedListener(scrollChangedListener);\n  }\n\n  /**\n   * Updates the {@link MaterialShapeDrawable}'s interpolation based on the {@link View}'s position\n   * in the containing {@link ScrollView}.\n   */\n  public void updateInterpolationForScreenPosition() {\n    if (containingScrollView == null) {\n      // No scroll view, no healing/growing.\n      return;\n    }\n    if (containingScrollView.getChildCount() == 0) {\n      // No container inside scroll view, no healing/growing.\n      throw new IllegalStateException(\n          \"Scroll bar must contain a child to calculate interpolation.\");\n    }\n\n    containingScrollView.getLocationInWindow(scrollLocation);\n    containingScrollView.getChildAt(0).getLocationInWindow(containerLocation);\n    int y = shapedView.getTop() - scrollLocation[1] + containerLocation[1];\n    int viewHeight = shapedView.getHeight();\n    int windowHeight = containingScrollView.getHeight();\n\n    // Off the top of the screen.\n    if (y < 0) {\n      materialShapeDrawable.setInterpolation(\n          Math.max(0f, Math.min(1f, 1f + (float) y / (float) viewHeight)));\n      shapedView.invalidate();\n    } else if (y + viewHeight > windowHeight) {\n      int distanceOffScreen = y + viewHeight - windowHeight;\n      materialShapeDrawable.setInterpolation(\n          Math.max(0f, Math.min(1f, 1f - (float) distanceOffScreen / (float) viewHeight)));","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/shape/InterpolateOnScrollPositionChangeHelper.java#L89-L125","documentation":"InterpolateOnScrollPositionChangeHelper.updateInterpolationForScreenPosition() throws IllegalStateException when the tracked ScrollView exists but has zero children. The helper computes corner 'healing/growing' interpolation from the offset between the ScrollView and its first child; with no child, childAt(0) would NPE, so the library throws a descriptive state exception instead.","triggerScenarios":"Calling setUpdateAccessibilityNotificationType... no — attaching MaterialShapeDrawable interpolation tracking via view.setOnScrollChangeListener / updateInterpolationForScreenPosition() against a ScrollView whose content was removed (e.g. during a swap or before content loads).","commonSituations":"Corner-treated cards inside a ScrollView whose child is replaced dynamically and briefly removed; calling the update before setContentView/inflation completes; viewpager fragment where the scroll content is cleared on destroy and a pending scroll callback still fires.","solutions":["Ensure the ScrollView always keeps exactly one container child (a vertical LinearLayout) and swap that container's children instead of removing the container.","Defer attaching the scroll-position listener until the ScrollView content is inflated.","Remove the listener (or null the helper's scroll view reference) before clearing scroll content."],"exampleFix":"<!-- before -->\n<ScrollView android:id=\"@+id/scroll\">\n    <!-- children swapped dynamically, sometimes empty -->\n</ScrollView>\n\n<!-- after -->\n<ScrollView android:id=\"@+id/scroll\">\n    <LinearLayout android:id=\"@+id/scrollContent\">\n        <!-- swap children inside this container; container never removed -->\n    </LinearLayout>\n</ScrollView>","handlingStrategy":"validation","validationCode":"if (scrollView.getChildCount() > 0) {\n  helper.updateInterpolationForScreenPosition();\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep exactly one non-removable container child inside every ScrollView used with corner interpolation.","Register scroll listeners after content inflation completes.","Clear listeners when tearing down dynamic content."],"tags":["android","material-components","shape","scrollview","state"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}