Skip to content

Crash in DraggableScrollableController.animateTo #125709

Closed

Description

@Piinks

b/279930163

Customer reports a crash happening with this stack trace:

flutter: The following _TypeError was thrown while notifying listeners for AnimationController:
flutter: Null check operator used on a null value
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      DraggableScrollableController.animateTo.<anonymous closure> (package:flutter/src/widgets/draggable_scrollable_sheet.dart:135:26)
flutter: #1      AnimationLocalListenersMixin.notifyListeners (package:flutter/src/animation/listener_helpers.dart:161:19)
flutter: #2      AnimationController._tick (package:flutter/src/animation/animation_controller.dart:830:5)
flutter: #3      Ticker._tick (package:flutter/src/scheduler/ticker.dart:249:12)
flutter: #4      SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1289:15)
flutter: #5      SchedulerBinding.handleBeginFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:1141:11)
flutter: #6      _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:625:13)
flutter: #7      SchedulerBinding.handleBeginFrame (package:flutter/src/scheduler/binding.dart:1139:17)
flutter: #8      SchedulerBinding._handleBeginFrame (package:flutter/src/scheduler/binding.dart:1056:5)
flutter: #9      _invoke1 (dart:ui/hooks.dart:158:13)
flutter: #10     PlatformDispatcher._beginFrame (dart:ui/platform_dispatcher.dart:337:5)
flutter: #11     _beginFrame (dart:ui/hooks.dart:101:31)

I have not been able to reproduce the issue.

In the customer app, the scroll controller is shared across two different DraggableScrollableSheets that are switched out as they expand and collapse.
There is a button at the top of the sheet that triggers the _controller.animateTo in order to collapse and expand it.
There is also a change in the sheets' extents happening in response to scroll notifications that are listening to the sheet.

Similar to #112020

Activity

  1. added
    c: crashStack traces logged to the console
    frameworkflutter/packages/flutter repository. See also f: labels.
    f: scrollingViewports, list views, slivers, etc.
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Apr 28, 2023
  2. Piinks commented on Apr 28, 2023

    @Piinks
    ContributorAuthor

    This is the code I have been trying to reproduce with, but this asserts against a shared controller before the sheets are swapped out. I have asked the customer to take a look and provide more information

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return const MaterialApp(home: MyHomePage());
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key});
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      final _controller = DraggableScrollableController();
      bool useExpanded = false;
      final _maximizedInitialExtent = 1.00;
      final _minimizedSheetBaseHeight = 104.0;
      final _sheetAnimationDuration = const Duration(milliseconds: 200);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('DraggableScrollableSheet'),
          ),
          body: NotificationListener<DraggableScrollableNotification>(
            onNotification: (scrollNotification) {
                if (scrollNotification.extent == scrollNotification.minExtent) {
                  print('Fully closed');
                  setState((){ useExpanded = false; });
                } else if (scrollNotification.extent == scrollNotification.maxExtent) {
                  print('Fully expanded');
                  setState((){ useExpanded = true; });
                }
                return true;
              },
            child: !useExpanded
            ? DraggableScrollableSheet(
              initialChildSize: 0.25,
              minChildSize: 0.25,
              controller: _controller,
              snap: true,
              snapSizes: const <double>[0.25, 1.0],
              builder: (BuildContext context, ScrollController scrollController) {
                return Container(
                  color: Colors.red[100],
                  child: ListView.builder(
                    controller: scrollController,
                    itemCount: 25,
                    itemBuilder: (BuildContext context, int index) {
                      if (index == 0) {
                        return TextButton(
                          child: const Text('Tap'),
                          onPressed: () => _controller.animateTo(
                            useExpanded
                                ? _calculateTrueMinimizedExtent(context: context)
                                : _maximizedInitialExtent,
                            duration: _sheetAnimationDuration,
                            curve: Curves.bounceInOut,
                          ),
                        );
                      }
                      return ListTile(title: Text('Item $index'));
                    },
                  ),
                );
              },
            )
            : Stack(
              children: [
                DraggableScrollableSheet(
                  initialChildSize: 1,
                  minChildSize: 0.25,
                  controller: _controller,
                  snap: true,
                  snapSizes: const <double>[0.25, 1.0],
                  builder: (BuildContext context, ScrollController scrollController) {
                    return Container(
                      color: Colors.blue[100],
                      child: ListView.builder(
                        controller: scrollController,
                        itemCount: 25,
                        itemBuilder: (BuildContext context, int index) {
                          if (index == 0) {
                        return TextButton(
                          child: const Text('Tap'),
                          onPressed: () => _controller.animateTo(
                            useExpanded
                                ? _calculateTrueMinimizedExtent(context: context)
                                : _maximizedInitialExtent,
                            duration: _sheetAnimationDuration,
                            curve: Curves.bounceInOut,
                          ),
                        );
                      }
                          return SizedBox(height: 50, child: Text('Item $index'));
                        },
                      ),
                    );
                  },
                ),
              ],
            ),
          ),
        );
      }
    
      double _calculateTrueMinimizedExtent({required BuildContext context}) {
        final screenHeight = MediaQuery.of(context).size.height;
        final sheetHeightPercentage = _minimizedSheetBaseHeight / screenHeight;
        return sheetHeightPercentage;
      }
    }
    
  3. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Apr 28, 2023
  4. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Apr 28, 2023
  5. dnfield commented on Apr 28, 2023

    @dnfield
    Contributor

    I have a test case in the linked PR, but I can make this happen by causing didUpdateWidget to happen during an animateTo.

  6. dnfield commented on Apr 28, 2023

    @dnfield
    Contributor

    We didn't get coverage of that because the existing test that exercised didUpdateWidget called jumpTo.

  7. self-assigned this
    on Apr 29, 2023
  8. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Apr 29, 2023
  9. github-actions commented on May 13, 2023

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  10. locked as resolved and limited conversation to collaborators on May 13, 2023
  11. added
    P0Critical issues such as a build break or regression
    and removed on Jun 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P0Critical issues such as a build break or regressiona: animationAnimation APIsc: crashStack traces logged to the consolecustomer: chalk (g3)f: scrollingViewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions