慢颤动GridView

时间:2020-04-29 23:33:40

标签: android ios flutter dart flutter-layout

我需要创建一个52x80的正方形方块网格。看起来像这样:

enter image description here

但是在仿真器中开发时性能特别慢(超过1秒的“滞后”)。我了解Flutter代码在物理设备上的发布模式下运行得更快,在我的情况下,如果设备是新设备,也是如此。但是,如果设备使用了几年(例如,三星Galaxy S8或iPhone 8),则在加载视图和滚动时会有令人沮丧的明显时间。而且我不能那样发布我的应用程序。我正在这样构建GridView:

  GridView.count(
    shrinkWrap: true,
    primary: false,
    padding: const EdgeInsets.all(5.0),
    crossAxisCount: 52,
    crossAxisSpacing: 1.0,
    mainAxisSpacing: 1.0,
    addAutomaticKeepAlives: true,
    children: blocks.map((block) => // blocks is just a list of 4160 objects
      FlatButton(
        child: null,
        color: block.backgroundColor,
        onPressed: () {
          // open a new route
        },
        splashColor: Colors.transparent,  
        highlightColor: Colors.transparent
      )
    ).toList()
  )

我尝试将FlatButton换成ImageSizedBox,这会有所帮助。关于如何提高速度的任何建议?

3 个答案:

答案 0 :(得分:3)

如果您需要向团伙添加onTap行为,则可以使用CustomPainter小部件创建自己的CustomGridView,并绘制所有项目并添加一个手势检测器并计算触摸位置

enter image description here enter image description here

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        backgroundColor: Colors.black,
        body: SafeArea(
          child: MyHomePage(),
        ),
      ),
    );
  }
}

final int redCount = 728;
final int greyCount = 3021;
final int allCount = 4160;
final int crossAxisCount = 52;

enum BlockTypes {
  red,
  gray,
  green,
  yellow,
}

class MyHomePage extends StatefulWidget {
  MyHomePage()
      : blocks = List<BlockTypes>.generate(allCount, (index) {
          if (index < redCount) {
            return BlockTypes.red;
          } else if (index < redCount + greyCount) {
            return BlockTypes.gray;
          }
          return BlockTypes.green;
        });

  final List<BlockTypes> blocks;

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

class _MyHomePageState extends State<MyHomePage> {
  int columnsCount;
  double blocSize;

  int clickedIndex;
  Offset clickOffset;
  bool hasSizes = false;
  List<BlockTypes> blocks;
  final ScrollController scrollController = ScrollController();

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
    blocks = widget.blocks;
    super.initState();
  }

  void _afterLayout(_) {
    blocSize = context.size.width / crossAxisCount;
    columnsCount = (allCount / crossAxisCount).ceil();
    setState(() {
      hasSizes = true;
    });
  }

  void onTapDown(TapDownDetails details) {
    final RenderBox box = context.findRenderObject();
    clickOffset = box.globalToLocal(details.globalPosition);
  }

  void onTap() {
    final dx = clickOffset.dx;
    final dy = clickOffset.dy + scrollController.offset;
    final tapedRow = (dx / blocSize).floor();
    final tapedColumn = (dy / blocSize).floor();
    clickedIndex = tapedColumn * crossAxisCount + tapedRow;

    setState(() {
      blocks[clickedIndex] = BlockTypes.yellow;
    });
  }

  @override
  Widget build(BuildContext context) {
    print(blocSize);
    return hasSizes
        ? SingleChildScrollView(
            controller: scrollController,
            child: GestureDetector(
              onTapDown: onTapDown,
              onTap: onTap,
              child: CustomPaint(
                size: Size(
                  MediaQuery.of(context).size.width,
                  columnsCount * blocSize,
                ),
                painter: CustomGridView(
                  blocs: widget.blocks,
                  columnsCount: columnsCount,
                  blocSize: blocSize,
                ),
              ),
            ),
          )
        : Container();
  }
}

class CustomGridView extends CustomPainter {
  final double gap = 1;
  final Paint painter = Paint()
    ..strokeWidth = 1
    ..style = PaintingStyle.fill;

  final int columnsCount;
  final double blocSize;
  final List<BlockTypes> blocs;

  CustomGridView({this.columnsCount, this.blocSize, this.blocs});

  @override
  void paint(Canvas canvas, Size size) {
    blocs.asMap().forEach((index, bloc) {
      setColor(bloc);
      canvas.drawRRect(
          RRect.fromRectAndRadius(
              Rect.fromLTWH(
                getLeft(index),
                getTop(index),
                blocSize - gap,
                blocSize - gap,
              ),
              Radius.circular(1.0)),
          painter);
    });
  }

  double getTop(int index) {
    return (index / crossAxisCount).floor().toDouble() * blocSize;
  }

  double getLeft(int index) {
    return (index % crossAxisCount).floor().toDouble() * blocSize;
  }

  @override
  bool shouldRepaint(CustomGridView oldDelegate) => true;
  @override
  bool shouldRebuildSemantics(CustomGridView oldDelegate) => true;

  void setColor(BlockTypes bloc) {
    switch (bloc) {
      case BlockTypes.red:
        painter.color = Colors.red;
        break;
      case BlockTypes.gray:
        painter.color = Colors.grey;
        break;
      case BlockTypes.green:
        painter.color = Colors.green;
        break;
      case BlockTypes.yellow:
        painter.color = Colors.yellow;
        break;
    }
  }
}

答案 1 :(得分:0)

要查看您的应用在设备上运行的速度如何,可以在Android Studio的“配置文件”中运行它。它将像在没有所有权限的情况下构建应用程序一样运行它。

enter image description here

答案 2 :(得分:0)

GridView.builder()非常适合生成包含大量项目的网格视图。

在这种情况下,使用GridView.count效率不高。而是使用GridView.builder,它将提高性能,因为将根据需要生成项目。

查看官方文件

GridView.builder构造可创建一个可滚动的2D窗口小部件数组,这些数组按需创建。 该构造函数适用于具有大量(或无限个)子级的网格视图,因为仅针对那些实际可见的子级调用该构建器。

请参见下面的示例代码:

GridView.builder(
          gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
            // number of items on a row
            crossAxisCount: 52,
            // horizontal spacing between items
            crossAxisSpacing: 3,
            // vertical spacing between items
            mainAxisSpacing: 5,
          ),
          itemBuilder: (BuildContext context, int index) {
            // your list of objects here
            return blocks();
          },
        ),

我希望这会有所帮助。