在网格视图中颤动可扩展的瓷砖

Flutter expandable tiles inside grid view

我正在尝试在 flutter 上实现此功能,但老实说不知道该怎么做。几个星期以来我一直在努力弄明白,我尝试了 flutter_staggered_grid_view,这是最接近这个的,但这也没有帮助。有人知道如何实现这种效果吗?

您可以将 Wrap 小部件用作网格,并使用一些带有 AnimatedContainer 的自定义小部件来展开和缩回块。

//number of childs used in the example
static const itemCount = 8;

//list of each bloc expandable state, that is changed to trigger the animation of the AnimatedContainer 
List<bool> expandableState = List.generate(itemCount, (index) => false);

Widget bloc (double width, int index) {
  bool isExpanded = expandableState[index];

  return GestureDetector(
    onTap: () {
      setState(() {
        //changing the current expandableState
        expandableState[index] = !isExpanded;
      });
    },
    child: AnimatedContainer(
      duration: Duration(milliseconds: 200),
      margin: const EdgeInsets.all(20.0),
      width: !isExpanded ? width * 0.4 : width * 0.8,
      height: !isExpanded ? width * 0.4 : width * 0.8,
      color: Colors.red,
    ),
  );
}

@override
Widget build(BuildContext context) {
  double width = MediaQuery.of(context).size.width;

  return Scaffold(
    body: Align(
      child: SingleChildScrollView(
        child: Wrap(
          children: List.generate(itemCount, (index) {
            return bloc(width, index);
          }),
        ),
      ),
    ),
  );
}

您可以使用 Wrap 小部件来实现结果。请看下面的代码。

import 'package:flutter/material.dart';

final Color darkBlue = const Color.fromARGB(255, 18, 32, 47);

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(title: const Text("Demo")),
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  final int _cells = 8;
  final double _containerSizeSmall = 75;
  final double _containerSizeLarge = 170;
  final double _padding = 10;
  int _clicked = 0;
  @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    return SingleChildScrollView(
      child: Container(
        height: size.height,
        width: 240,
        child: Wrap(
          children: List.generate(
            _cells,
            (col) => Padding(
              padding: EdgeInsets.all(_padding),
              child: GestureDetector(
                onTap: () {
                  setState(() {
                    _clicked != col + 1 ? _clicked = col + 1 : _clicked = 0;
                  });
                },
                child: Container(
                  height: _clicked == col + 1
                      ? _containerSizeLarge
                      : _containerSizeSmall,
                  width: _clicked == col + 1
                      ? _containerSizeLarge
                      : _containerSizeSmall,
                  decoration: const BoxDecoration(
                    color: Colors.blue,
                    borderRadius: const BorderRadius.all(
                      const Radius.circular(5),
                    ),
                  ),
                  child: Center(child: Text('${col + 1}')),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

您可以列出应展开的项目并将它们相应地放置在网格视图中(例如使用 flutter_staggered_grid_view)。

我编辑了编写的示例 in the library docs 以实现以下结果:

基本上,

  1. 创建一个 StatefulWidget 并向其添加一个列表 (_expandedIndices)。该列表的目的是跟踪展开的项目的索引。

  2. 在网格单元格上添加一个 GestureDetector 以检测列表中的点击和 add/remove 索引(如果索引不存在,则将其添加到列表中,否则删除它)。

Don't forget to put the code that updates the list inside a setState.

  1. staggeredTileBuilder 中配置 crossAxisCellCountmainAxisCellCount 基于 index 中的项目是否应该展开。
class StaggeredGridViewWithExpandableCells extends StatefulWidget {
  @override
  _StaggeredGridViewWithExpandableCellsState createState() =>
      _StaggeredGridViewWithExpandableCellsState();
}

class _StaggeredGridViewWithExpandableCellsState
    extends State<StaggeredGridViewWithExpandableCells> {
  final _expandedIndices = Set<int>();

  @override
  Widget build(BuildContext context) {
    return StaggeredGridView.countBuilder(
      crossAxisCount: 4,
      itemCount: 16,
      itemBuilder: (BuildContext context, int index) => GestureDetector(
        onTap: () => setState(() => _expandedIndices.contains(index) ? _expandedIndices.remove(index) : _expandedIndices.add(index)),
        child: new Container(
            color: Colors.green,
            child: new Center(
              child: new CircleAvatar(
                backgroundColor: Colors.white,
                child: new Text('$index'),
              ),
            )),
      ),
      staggeredTileBuilder: (int index) =>
          new StaggeredTile.count(_expandedIndices.contains(index) ? 4 : 2, 1),
      mainAxisSpacing: 4.0,
      crossAxisSpacing: 4.0,
    );
  }
}