Flutter GridView 计数更新给出了错误的滚动位置
Flutter GridView count update gives wrong scroll position
我是 Flutter 的新手,正在尝试实现网格列表。
我用 GridView
来做到这一点。
我希望我的 GridView
默认情况下每行显示 2 个项目
并且当用户单击 AppBar
上的按钮时,
我想更改 GridView
的计数
这样每行只能显示一项。
要实现此行为,
我创建了 MyApp
、_GridCountButton
、MainList
。
MyApp
是包含 _gridCount
.
的 StatefulWidget
_GridCountButton
是一个 StatelessWidget
并从 MyApp
接收侦听器并在按下时调用侦听器。
MainList
是 GridView
.
如您所见,网格的更改有效,
但是 GridView
的滚动位置不是我想要的。
好像保持了滚动的绝对值
我怎样才能使屏幕上的第一项保持相同?
我大致解决了我的问题,所以这个解决方案在其他情况下可能不起作用。
最佳解决方案可能是
最好的解决方案可能是使用 ScrollController
来侦听并移动到使用项目的 height
计算的特定偏移量。
要获取项目的 height
,我在 initState()
回调中找到了执行此操作的方法,但我创建了列表 StatelessWidget
,所以它没有 initState()
.
我做了什么
我的情况
所以我只是使用项目大小的比率来获得适当的偏移量。
在我的例子中,我必须每行显示 1 或 2 个项目,分别为 grid1
和 grid2
。
所以我将grid1
和grid2
的偏移量存储到offset
和offset2
。
那么 offset1
和 offset2
之间的关系将是 offset1 = offset2*4
,因为 grid1
只能显示 1 个项目,而 grid2
可以显示 4 个项目同样的 space.
为什么不只是 offset
?
我尝试只使用一个 offset
变量来存储 grid1
的偏移量。
调用滚动事件时,我计算 offset
始终保持 grid1
的偏移量。
但是,当没有滚动条时,不会调用滚动事件。
所以当我
- 从
grid1
切换到 grid2
,
- 不要做任何滚动,
- 从
grid2
切换到 grid1
,
offset
的值保持不变,被识别为grid2
的偏移量。
所以我将 offset1
和 offset2
分开,以确保哪个偏移量与哪个网格匹配。
与offset1
和offset2
现在我有了正确更新的正确值,我现在可以设置这个值来设置正确的偏移量。
当我调用 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)));
}
});
},
);
});
}
}
我是 Flutter 的新手,正在尝试实现网格列表。
我用 GridView
来做到这一点。
我希望我的 GridView
默认情况下每行显示 2 个项目
并且当用户单击 AppBar
上的按钮时,
我想更改 GridView
这样每行只能显示一项。
要实现此行为,
我创建了 MyApp
、_GridCountButton
、MainList
。
MyApp
是包含 _gridCount
.
StatefulWidget
_GridCountButton
是一个 StatelessWidget
并从 MyApp
接收侦听器并在按下时调用侦听器。
MainList
是 GridView
.
如您所见,网格的更改有效,
但是 GridView
的滚动位置不是我想要的。
好像保持了滚动的绝对值
我怎样才能使屏幕上的第一项保持相同?
我大致解决了我的问题,所以这个解决方案在其他情况下可能不起作用。
最佳解决方案可能是
最好的解决方案可能是使用 ScrollController
来侦听并移动到使用项目的 height
计算的特定偏移量。
要获取项目的 height
,我在 initState()
回调中找到了执行此操作的方法,但我创建了列表 StatelessWidget
,所以它没有 initState()
.
我做了什么
我的情况
所以我只是使用项目大小的比率来获得适当的偏移量。
在我的例子中,我必须每行显示 1 或 2 个项目,分别为 grid1
和 grid2
。
所以我将grid1
和grid2
的偏移量存储到offset
和offset2
。
那么 offset1
和 offset2
之间的关系将是 offset1 = offset2*4
,因为 grid1
只能显示 1 个项目,而 grid2
可以显示 4 个项目同样的 space.
为什么不只是 offset
?
我尝试只使用一个 offset
变量来存储 grid1
的偏移量。
调用滚动事件时,我计算 offset
始终保持 grid1
的偏移量。
但是,当没有滚动条时,不会调用滚动事件。
所以当我
- 从
grid1
切换到grid2
, - 不要做任何滚动,
- 从
grid2
切换到grid1
,
offset
的值保持不变,被识别为grid2
的偏移量。
所以我将 offset1
和 offset2
分开,以确保哪个偏移量与哪个网格匹配。
与offset1
和offset2
现在我有了正确更新的正确值,我现在可以设置这个值来设置正确的偏移量。
当我调用 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)));
}
});
},
);
});
}
}