简体   繁体   English

如何在具有许多文本小部件的颤动小部件中提高渲染性能

[英]How improve rendering performance in a flutter widget with many text widgets

we have a performance problem in our calendar widget.我们的日历小部件存在性能问题。 We want to display 3 Years in a scroll view.我们想在滚动视图中显示 3 年。 Each day should be displayed and some days should be marked.每一天都应该被显示出来,有些日子应该被标记出来。 The problem is, that the rendering time of this widget is on some devises up to 5 seconds.问题是,这个小部件的渲染时间在某些设备上长达 5 秒。 I think the problem is that we need over 1000 Text widgets to display it.我认为问题是我们需要超过 1000 个文本小部件来显示它。 Does someone have an idea how to improve it?有人知道如何改进它吗?

I have written a small sample app.我写了一个小示例应用程序。 There are many simplifications in it, like every month has 31 days and the layout is bad, but it shows what we want and that it is too slow.里面有很多简化,比如每个月有31天,布局不好,但是它显示了我们想要的东西,而且速度太慢了。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

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

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool year = false;

  @override
  Widget build(BuildContext context) {
    const Key currentYearKey = Key('currentYearKey');
    return Scaffold(
        floatingActionButton: FloatingActionButton(
            onPressed: () => setState(() {
                  year = !year;
                })),
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: year
            ? CustomScrollView(
                center: currentYearKey,
                slivers: [
                  SliverToBoxAdapter(
                    child: Column(
                      children: [Year(), Year()],
                    ),
                  ),
                  SliverToBoxAdapter(
                    child: Year(),
                    key: currentYearKey,
                  )
                ],
              )
            : Text("1"));
  }
}

class Year extends StatelessWidget {
  const Year({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text("Year XX"),
          ...List.generate(
            4,
            (rowIndex) => Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: List.generate(
                3,
                (columnIndex) {
                  return Expanded(
                      child: Month(
                    daySize: 14,
                    markedDays: [1, 3, 26, 30],
                  ));
                },
              ),
            ),
          ),
        ]);
  }
}

class Month extends StatelessWidget {
  const Month({required this.markedDays, required this.daySize, Key? key})
      : super(key: key);
  final List<int> markedDays;
  final double daySize;

  @override
  Widget build(BuildContext context) {
    return GridView.count(
        padding: EdgeInsets.zero,
        crossAxisCount: 7,
        shrinkWrap: true,
        physics: const NeverScrollableScrollPhysics(),
        children: List.generate(31, (index) {
          final bool isMarked = markedDays.contains(index);
          return Center(
            child: Container(
              height: daySize,
              width: daySize,
              decoration:
                  isMarked ? BoxDecoration(color: Colors.lightBlue) : null,
              child: Text(
                "$index",
                style: isMarked ? TextStyle(fontWeight: FontWeight.bold) : null,
              ),
            ),
          );
        }));
  }
}

screenshot截屏

We tried to make as much as possible const, it improved it abit, and make it around 30% faster, but we need it much faster.我们尝试尽可能多地使用 const,它改进了一点,使它快了 30% 左右,但我们需要它快得多。 We also tried to replace the GridView in the month through a table or row/column construct, but it does not help.我们还尝试通过表格或行/列构造来替换月中的 GridView,但它没有帮助。

Instead of columns use ListView.builder , this helped me with long lists: https://docs.flutter.dev/cookbook/lists/long-lists而不是columns使用ListView.builder ,这帮助我处理了长列表: https ://docs.flutter.dev/cookbook/lists/long-lists

The solution was to compile it in release mode.解决方案是在发布模式下编译它。 It does still need some time to render, but much less.它确实仍然需要一些时间来渲染,但要少得多。 Thanks @rszf for the help.感谢@rszf 的帮助。

For those who have the same problem, and don't know the build modes, here is some information: https://docs.flutter.dev/testing/build-modes对于那些有同样问题但不知道构建模式的人,这里有一些信息: https ://docs.flutter.dev/testing/build-modes

In this case you defiantly must use GridView.builder / ListView.builder.在这种情况下,您必须坚决使用 GridView.builder / ListView.builder。

This will lead to build widgets on demand.这将导致按需构建小部件。 Instead of building everything at once which is Bad practice.而不是一次构建所有东西,这是不好的做法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM