DraggableScrollableSheet восстанавливает всех дочерних элементов каждый кадр при перетаскивании

Я пытаюсь реализовать DraggableScrollableSheet с двумя вложенными прокручиваемыми списками.

Я не могу использовать готовый класс NestedScrollView (я уже пробовал его, но мне не удалось заставить его работать, поскольку он, похоже, создан для одной предыдущей полосы заголовка и только одного прокручиваемого списка).

Мой подход с классом CustomScrollView обычно работает, но, к сожалению, возникает другая проблема: каждый раз, когда пользователь перетаскивает лист, все фрагменты восстанавливаются с каждым кадром. Что ужасно медленно.

Я открыл простой тестовый пример, чтобы исключить, что это не ошибка какой-либо сложной логики виджетов / поставщиков / потребителей и т. Д. Даже с этими простыми виджетами все фрагменты восстанавливаются один раз за кадр ...

Это ошибка во фреймворке или что я здесь делаю не так?

Большое тебе спасибо...

    import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: DraggableScrollableActuator(child: MyHomePage(title: 'Flutter Demo Home Page')),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween<Offset> _tween = Tween(begin: Offset(0, 1), end: Offset(0, 0));

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 300));
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Stack(children: [
      SlideTransition(
        position: _tween.animate(_controller),
        child: MyPopUpSheet(),
      ),
      Center(
        child: IconButton(
            icon: const Icon(Icons.info),
            onPressed: () {
              setState(() {
                if (_controller.isDismissed)
                  _controller.forward();
                else if (_controller.isCompleted) _controller.reverse().then((value) => _controller.reset());
              });
            }),
      ),
    ]));
  }
}

class MyPopUpSheet extends StatelessWidget {
  ScrollController _scrollController; //Needed for

  @override
  Widget build(BuildContext context) {
    print("MyPopUpSheet.build()");
    return Material(
      elevation: 4,
      shadowColor: Colors.orange,
      child: DraggableScrollableSheet(
        expand: true,
        initialChildSize: 0.4,
        minChildSize: 0.4,
        maxChildSize: 1.0,
        builder: (ctx, scrollController) {
          _scrollController = scrollController;
          return CustomScrollView(
            shrinkWrap: true,
            controller: _scrollController,
            slivers: [
              SliverToBoxAdapter(child: Test(Colors.deepOrange)),
              SliverToBoxAdapter(child: Test(Colors.red)),
              SliverToBoxAdapter(child: Test(Colors.green)),
              SliverToBoxAdapter(child: Test(Colors.purpleAccent)),
              SliverToBoxAdapter(child: Test(Colors.amberAccent))
            ],
          );
        },
      ),
    );
  }
}
    
 class Test extends StatelessWidget {
  final Color color;
  Test(this.color);
  
  @override
  Widget build(BuildContext context) {
    print("Test.build()");
    return Container(height: 100, color: color);
  }
}

person JohnnyRainbow    schedule 28.09.2020    source источник
comment
такая же проблема здесь. уже нашли какие-то решения?   -  person Ganesh Rathinavel    schedule 03.10.2020
comment
К сожалению, нет: / Если этого достаточно для ваших нужд, просто используйте NestedScrollview вместо CustomScrollview. Последний не производит ненужных перестроек.   -  person JohnnyRainbow    schedule 05.10.2020
comment
Я сообщил о проблеме с Flutter, и это оказалось ошибкой. github.com/flutter/flutter/issues/67219   -  person Ganesh Rathinavel    schedule 05.10.2020
comment
Прохладный. Посмотрим, что там происходит ..   -  person JohnnyRainbow    schedule 05.10.2020
comment
Кто-нибудь тем временем нашел решение?   -  person Oren    schedule 28.01.2021


Ответы (2)


Я столкнулся с той же проблемой и нашел обходной путь, который не останавливает перестройку, но кэширует дочерний элемент и устраняет рывки прокрутки. Что сработало, так это сохранить виджет внутри конструктора в переменной и вернуть эту переменную из построителя.

Общее исправление

var child;
return DraggableScrollableSheet(
  expand: true,
  initialChildSize: 0.4,
  minChildSize: 0.4,
  maxChildSize: 1.0,
  builder: (ctx, scrollController) {
    if(child == null) {
      child = SomeWidget();
    }
    return child;
  }
);

Исправление, относящееся к этой проблеме

var child;
return DraggableScrollableSheet(
  expand: true,
  initialChildSize: 0.4,
  minChildSize: 0.4,
  maxChildSize: 1.0,
  builder: (ctx, scrollController) {
    if(child == null) {
      child = CustomScrollView(
        shrinkWrap: true,
        controller: _scrollController,
        slivers: [
          SliverToBoxAdapter(child: Test(Colors.deepOrange)),
          SliverToBoxAdapter(child: Test(Colors.red)),
          SliverToBoxAdapter(child: Test(Colors.green)),
          SliverToBoxAdapter(child: Test(Colors.purpleAccent)),
          SliverToBoxAdapter(child: Test(Colors.amberAccent))
        ],
      );
    }
    return child;
  }
);
person Muhammad Abdur Rafay Sajid    schedule 06.05.2021

Я не нашел хорошего решения, поэтому использовал пакет сдвижных панелей.

person Hamdam Muqimov    schedule 07.01.2021