Repository: flutter
Issue: Scrollable.of() was called with a context that does not contain a Scrollable widget.
Labels: c: crash,framework,package,p: animations,team-ecosystem,has reproducible steps,a: null-safety,P2,found in release: 3.3,found in release: 3.6,triaged-ecosystem

## Steps to Reproduce

<!-- Please include full steps to reproduce so that we can reproduce the problem. -->

1. In a newly created flutter project Run `flutter pub add animations`
2. Run the below code sample which is the same as the [official parallax example](https://docs.flutter.dev/cookbook/effects/parallax-scrolling) with just LocationListItem wrapped in OpenContainer.
```dart
 OpenContainer<bool>(
    openBuilder:
    (BuildContext context, VoidCallback openContainer) {
        return const LocationDetailView();
    },
     tappable: true,
     transitionType: ContainerTransitionType.fadeThrough,
     closedBuilder:
     (BuildContext context, VoidCallback openContainer) {
          return LocationListItem(
              imageUrl: location.imageUrl,
              name: location.name,
              country: location.place,
          );
     })
```
3. Click on the image

**Expected results:**: The code should run without error 

**Actual results:**: Null check Exception occurs.

<details>
<summary>Code sample</summary>

<!--
      Please create a minimal reproducible sample that shows the problem
      and attach it below between the lines with the backticks.

      To create it you can use `flutter create bug` command and update the `main.dart` file.

      Alternatively, you can use https://dartpad.dev/
      which is capable of creating and running small Flutter apps.

      Without this we will unlikely be able to progress on the issue, and because of that
      we regretfully will have to close it.
-->

```dart
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: const Scaffold(
        body: Center(
          child: ExampleParallax(),
        ),
      ),
    );
  }
}

class ExampleParallax extends StatelessWidget {
  const ExampleParallax({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: [
          for (final location in locations)
            OpenContainer<bool>(
                openBuilder:
                    (BuildContext context, VoidCallback openContainer) {
                  return const LocationDetailView();
                },
                tappable: true,
                transitionType: ContainerTransitionType.fadeThrough,
                closedBuilder:
                    (BuildContext context, VoidCallback openContainer) {
                  return LocationListItem(
                    imageUrl: location.imageUrl,
                    name: location.name,
                    country: location.place,
                  );
                })
        ],
      ),
    );
  }
}

class LocationListItem extends StatelessWidget {
  LocationListItem({
    super.key,
    required this.imageUrl,
    required this.name,
    required this.country,
  });

  final String imageUrl;
  final String name;
  final String country;
  final GlobalKey _backgroundImageKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
      child: AspectRatio(
        aspectRatio: 16 / 9,
        child: ClipRRect(
          borderRadius: BorderRadius.circular(16),
          child: Stack(
            children: [
              _buildParallaxBackground(context),
              _buildGradient(),
              _buildTitleAndSubtitle(),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildParallaxBackground(BuildContext context) {
    return Flow(
      delegate: ParallaxFlowDelegate(
        scrollable: Scrollable.of(context)!,
        listItemContext: context,
        backgroundImageKey: _backgroundImageKey,
      ),
      children: [
        Image.network(
          imageUrl,
          key: _backgroundImageKey,
          fit: BoxFit.cover,
        ),
      ],
    );
  }

  Widget _buildGradient() {
    return Positioned.fill(
      child: DecoratedBox(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            colors: [Colors.transparent, Colors.black.withOpacity(0.7)],
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            stops: const [0.6, 0.95],
          ),
        ),
      ),
    );
  }

  Widget _buildTitleAndSubtitle() {
    return Positioned(
      left: 20,
      bottom: 20,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            name,
            style: const TextStyle(
              color: Colors.white,
              fontSize: 20,
              fontWeight: FontWeight.bold,
            ),
          ),
          Text(
            country,
            style: const TextStyle(
              color: Colors.white,
              fontSize: 14,
            ),
          ),
        ],
      ),
    );
  }
}

class ParallaxFlowDelegate extends FlowDelegate {
  ParallaxFlowDelegate({
    required this.scrollable,
    required this.listItemContext,
    required this.backgroundImageKey,
  }) : super(repaint: scrollable.position);

  final ScrollableState scrollable;
  final BuildContext listItemContext;
  final GlobalKey backgroundImageKey;

  @override
  BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) {
    return BoxConstraints.tightFor(
      width: constraints.maxWidth,
    );
  }

  @override
  void paintChildren(FlowPaintingContext context) {
    final scrollableBox = scrollable.context.findRenderObject() as RenderBox;
    final listItemBox = listItemContext.findRenderObject() as RenderBox;
    final listItemOffset = listItemBox.localToGlobal(
        listItemBox.size.centerLeft(Offset.zero),
        ancestor: scrollableBox);
    final viewportDimension = scrollable.position.viewportDimension;
    final scrollFraction =
        (listItemOffset.dy / viewportDimension).clamp(0.0, 1.0);
    final verticalAlignment = Alignment(0.0, scrollFraction * 2 - 1);
    final backgroundSize =
        (backgroundImageKey.currentContext!.findRenderObject() as RenderBox)
            .size;
    final listItemSize = context.size;
    final childRect =
        verticalAlignment.inscribe(backgroundSize, Offset.zero & listItemSize);
    context.paintChild(
      0,
      transform:
          Transform.translate(offset: Offset(0.0, childRect.top)).transform,
    );
  }

  @override
  bool shouldRepaint(ParallaxFlowDelegate oldDelegate) {
    return scrollable != oldDelegate.scrollable ||
        listItemContext != oldDelegate.listItemContext ||
        backgroundImageKey != oldDelegate.backgroundImageKey;
  }
}

class Parallax extends SingleChildRenderObjectWidget {
  const Parallax({
    super.key,
    required Widget background,
  }) : super(child: background);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return RenderParallax(scrollable: Scrollable.of(context)!);
  }

  @override
  void updateRenderObject(
      BuildContext context, covariant RenderParallax renderObject) {
    renderObject.scrollable = Scrollable.of(context)!;
  }
}

class ParallaxParentData extends ContainerBoxParentData<RenderBox> {}

class RenderParallax extends RenderBox
    with RenderObjectWithChildMixin<RenderBox>, RenderProxyBoxMixin {
  RenderParallax({
    required ScrollableState scrollable,
  }) : _scrollable = scrollable;

  ScrollableState _scrollable;

  ScrollableState get scrollable => _scrollable;

  set scrollable(ScrollableState value) {
    if (value != _scrollable) {
      if (attached) {
        _scrollable.position.removeListener(markNeedsLayout);
      }
      _scrollable = value;
      if (attached) {
        _scrollable.position.addListener(markNeedsLayout);
      }
    }
  }

  @override
  void attach(covariant PipelineOwner owner) {
    super.attach(owner);
    _scrollable.position.addListener(markNeedsLayout);
  }

  @override
  void detach() {
    _scrollable.position.removeListener(markNeedsLayout);
    super.detach();
  }

  @override
  void setupParentData(covariant RenderObject child) {
    if (child.parentData is! ParallaxParentData) {
      child.parentData = ParallaxParentData();
    }
  }

  @override
  void performLayout() {
    size = constraints.biggest;
    final background = child!;
    final backgroundImageConstraints =
        BoxConstraints.tightFor(width: size.width);
    background.layout(backgroundImageConstraints, parentUsesSize: true);
    (background.parentData as ParallaxParentData).offset = Offset.zero;
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    // Get the size of the scrollable area.
    final viewportDimension = scrollable.position.viewportDimension;
    final scrollableBox = scrollable.context.findRenderObject() as RenderBox;
    final backgroundOffset =
        localToGlobal(size.centerLeft(Offset.zero), ancestor: scrollableBox);
    final scrollFraction =
        (backgroundOffset.dy / viewportDimension).clamp(0.0, 1.0);
    final verticalAlignment = Alignment(0.0, scrollFraction * 2 - 1);
    final background = child!;
    final backgroundSize = background.size;
    final listItemSize = size;
    final childRect =
        verticalAlignment.inscribe(backgroundSize, Offset.zero & listItemSize);
    context.paintChild(
        background,
        (background.parentData as ParallaxParentData).offset +
            offset +
            Offset(0.0, childRect.top));
  }
}

class Location {
  const Location({
    required this.name,
    required this.place,
    required this.imageUrl,
  });

  final String name;
  final String place;
  final String imageUrl;
}

const urlPrefix =
    'https://docs.flutter.dev/cookbook/img-files/effects/parallax';
const locations = [
  Location(
    name: 'Mount Rushmore',
    place: 'U.S.A',
    imageUrl: '$urlPrefix/01-mount-rushmore.jpg',
  ),
  Location(
    name: 'Gardens By The Bay',
    place: 'Singapore',
    imageUrl: '$urlPrefix/02-singapore.jpg',
  ),
  Location(
    name: 'Machu Picchu',
    place: 'Peru',
    imageUrl: '$urlPrefix/03-machu-picchu.jpg',
  ),
  Location(
    name: 'Vitznau',
    place: 'Switzerland',
    imageUrl: '$urlPrefix/04-vitznau.jpg',
  ),
  Location(
    name: 'Bali',
    place: 'Indonesia',
    imageUrl: '$urlPrefix/05-bali.jpg',
  ),
  Location(
    name: 'Mexico City',
    place: 'Mexico',
    imageUrl: '$urlPrefix/06-mexico-city.jpg',
  ),
  Location(
    name: 'Cairo',
    place: 'Egypt',
    imageUrl: '$urlPrefix/07-cairo.jpg',
  ),
];

class LocationDetailView extends StatefulWidget {
  const LocationDetailView({Key? key}) : super(key: key);

  @override
  State<LocationDetailView> createState() => _LocationDetailViewState();
}

class _LocationDetailViewState extends State<LocationDetailView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Parallax Detail'),
      ),
      body: Center(
        child: Container(
          color: Colors.red,
        ),
      ),
    );
  }
}
```

</details>

<details>
<summary>flutter doctor -v</summary>

```
[✓] Flutter (Channel master, 3.4.0-18.0.pre, on macOS 12.6 21G115 darwin-arm64, locale en-IN)
    • Flutter version 3.4.0-18.0.pre on channel master at /Users/mahesh/Development/flutter_master
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 069f504297 (3 months ago), 2022-08-30 18:20:09 -0700
    • Engine revision 0ef08a8525
    • Dart version 2.19.0 (build 2.19.0-152.0.dev)
    • DevTools version 2.16.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc4)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0-rc4
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14A400
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 61.2.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.70.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.53.20221101

[✓] Connected device (3 available)
    • iPhone 12 Pro (mobile) • 026D5789-9E78-4AD5-B1B2-3F8D4E7F65E4 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-14-5
      (simulator)
    • macOS (desktop)        • macos                                • darwin-arm64   • macOS 12.6 21G115 darwin-arm64
    • Chrome (web)           • chrome                               • web-javascript • Google Chrome 107.0.5304.110

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
```
</details> 

<details>
  <summary>Logs</summary>

<!-- Finally, paste the output of running `flutter doctor -v` here. -->

```Restarted application in 319ms.

════════ Exception caught by widgets library ═══════════════════════════════════
The following _CastError was thrown building LocationListItem(dirty):
Null check operator used on a null value

The relevant error-causing widget was
LocationListItem
When the exception was thrown, this was the stack
#0      LocationListItem._buildParallaxBackground
#1      LocationListItem.build
#2      StatelessElement.build
#3      ComponentElement.performRebuild
#4      Element.rebuild
#5      StatelessElement.update
#6      Element.updateChild
#7      ComponentElement.performRebuild
#8      Element.rebuild
#9      StatelessElement.update
#10     Element.updateChild
...     Normal element mounting (10 frames)
#20     Element.inflateWidget
#21     MultiChildRenderObjectElement.inflateWidget
#22     MultiChildRenderObjectElement.mount
...     Normal element mounting (231 frames)
#253    Element.inflateWidget
#254    MultiChildRenderObjectElement.inflateWidget
#255    Element.updateChild
#256    RenderObjectElement.updateChildren
#257    MultiChildRenderObjectElement.update
#258    Element.updateChild
#259    ComponentElement.performRebuild
#260    StatefulElement.performRebuild
#261    Element.rebuild
#262    StatefulElement.update
#263    Element.updateChild
#264    ComponentElement.performRebuild
#265    Element.rebuild
#266    ProxyElement.update
#267    Element.updateChild
#268    ComponentElement.performRebuild
#269    Element.rebuild
#270    ProxyElement.update
#271    _InheritedNotifierElement.update
#272    Element.updateChild
#273    SingleChildRenderObjectElement.update
#274    Element.updateChild
#275    ComponentElement.performRebuild
#276    StatefulElement.performRebuild
#277    Element.rebuild
#278    StatefulElement.update
#279    Element.updateChild
#280    SingleChildRenderObjectElement.update
#281    Element.updateChild
#282    SingleChildRenderObjectElement.update
#283    Element.updateChild
#284    ComponentElement.performRebuild
#285    Element.rebuild
#286    ProxyElement.update
#287    Element.updateChild
#288    ComponentElement.performRebuild
#289    StatefulElement.performRebuild
#290    Element.rebuild
#291    BuildOwner.buildScope
#292    WidgetsBinding.drawFrame
#293    RendererBinding._handlePersistentFrameCallback
#294    SchedulerBinding._invokeFrameCallback
#295    SchedulerBinding.handleDrawFrame
#296    SchedulerBinding._handleDrawFrame
#297    _invoke (dart:ui/hooks.dart:148:13)
#298    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#299    _drawFrame (dart:ui/hooks.dart:115:31)
════════════════════════════════════════════════════════════════════════════════
```

</details>

Potentially related to this PR: https://github.com/flutter/flutter/issues/1087



<!--
      Consider also attaching screenshots and/or videos to better
      illustrate the issue.

      You can upload them directly on GitHub.
      Beware that video file size is limited to 10MB.
-->