DraggableScrollableSheet拖动时每帧都会重建所有子级

问题描述

我正在尝试使用2个嵌套的可滚​​动列表实现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);
  }
}

解决方法

我遇到了同样的问题,并找到了一种解决方法,该方法不会停止重建,但会缓存子项并修复滚动卡顿。有效的是,将小部件存储在构建器中的变量中,并从构建器返回该变量。

一般修复

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,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;
  }
);
,

我没有找到好的解决方案,所以我使用了滑动面板包。