Flutter GridView 计数更新给出了错误的滚动位置

Flutter GridView count update gives wrong scroll position

我是 Flutter 的新手,正在尝试实现网格列表。

我用 GridView 来做到这一点。

我希望我的 GridView 默认情况下每行显示 2 个项目

并且当用户单击 AppBar 上的按钮时,

我想更改 GridView

的计数

这样每行只能显示一项。

要实现此行为,

我创建了 MyApp_GridCountButtonMainList

MyApp 是包含 _gridCount.

StatefulWidget

_GridCountButton 是一个 StatelessWidget 并从 MyApp 接收侦听器并在按下时调用侦听器。

MainListGridView.

如您所见,网格的更改有效,

但是 GridView 的滚动位置不是我想要的。

好像保持了滚动的绝对值

我怎样才能使屏幕上的第一项保持相同?

我大致解决了我的问题,所以这个解决方案在其他情况下可能不起作用。

最佳解决方案可能是

最好的解决方案可能是使用 ScrollController 来侦听并移动到使用项目的 height 计算的特定偏移量。

要获取项目的 height,我在 initState() 回调中找到了执行此操作的方法,但我创建了列表 StatelessWidget,所以它没有 initState().

我做了什么

我的情况

所以我只是使用项目大小的比率来获得适当的偏移量。

在我的例子中,我必须每行显示 1 或 2 个项目,分别为 grid1grid2

所以我将grid1grid2的偏移量存储到offsetoffset2

那么 offset1offset2 之间的关系将是 offset1 = offset2*4,因为 grid1 只能显示 1 个项目,而 grid2 可以显示 4 个项目同样的 space.

为什么不只是 offset

我尝试只使用一个 offset 变量来存储 grid1 的偏移量。

调用滚动事件时,我计算 offset 始终保持 grid1 的偏移量。

但是,当没有滚动条时,不会调用滚动事件。

所以当我

  1. grid1 切换到 grid2,
  2. 不要做任何滚动,
  3. grid2 切换到 grid1,

offset的值保持不变,被识别为grid2的偏移量。

所以我将 offset1offset2 分开,以确保哪个偏移量与哪个网格匹配。

offset1offset2

现在我有了正确更新的正确值,我现在可以设置这个值来设置正确的偏移量。

当我调用 setState 切换网格时,我添加了以下几行。

setState(() {
  double offset = 0.0; // offset to be set
  if(_gridCount == 2) {
    _gridCount = 1;
    offset = offset1; // set offset1
  } else {
    _gridCount = 2;
    offset = offset2; // set offset2
  }
  _scrollController.jumpTo(offset); // set proper offset
});

成功了!

请检查我对这个问题的尝试。当点击项目时,gridview 从双网格变为单网格,反之亦然。欢迎任何建议或更改。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter TabBar',
      home: new Home(),
      theme: new ThemeData(primaryColor: Colors.black),
    );
  }
}

class Home extends StatefulWidget {
  @override
  _HomeState createState() => new _HomeState();
}

class _HomeState extends State<Home> {
  ScrollController _scrollController;
  double _offset;
  double _doubleGridItemHeight = 100.0;
  double _singleGridItemHeight = 200.0;
  int _gridCount = 2;

  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController()
      ..addListener(() {
        print("offset = ${_scrollController.offset}");
        setState(() {
          _offset = _scrollController.offset;
        });
      });
  }

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
        controller: _scrollController,
        itemCount: 40,
        gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: _gridCount),
        itemBuilder: (BuildContext context, int index) {
          return new GestureDetector(
            child: Container(
              height: _gridCount == 1
                  ? _doubleGridItemHeight
                  : _singleGridItemHeight,
              child: new Card(
                elevation: 5.0,
                child: new Container(
                  alignment: Alignment.center,
                  child: new Text('Item $index'),
                ),
              ),
            ),
            onTap: () {
              setState(() {
                if (_gridCount == 2) {
                  _gridCount = 1;
                  // scrolling with animation
                  _scrollController.animateTo(
                      _offset +
                          ((index) *
                              (_doubleGridItemHeight + _singleGridItemHeight)),
                      curve: Curves.linear,
                      duration: Duration(milliseconds: 500));
                } else {
                  _gridCount = 2;
                  // scrolling without animation
                  _scrollController.jumpTo(_offset -
                      ((index) *
                          (_doubleGridItemHeight + _singleGridItemHeight)));
                }
              });
            },
          );
        });
  }
}