我正在尝试构建用户可以滚动浏览的帖子(例如Twitter或instagram类型的帖子)。在滚动时,他们可以单击其中一个帖子并导航到新页面。当他们从该页面返回导航时,我希望它们保持在ListView先前所在位置的相同位置。
问题
我目前无法阻止流窗口小部件重建并返回到滚动位置。我知道解决此问题的方法之一就是添加一个密钥。但是,我试图将键包括在ListView.builder中,但是它没有用。
问题 我应该在哪里包含密钥?我使用的钥匙类型正确吗?
class Stream extends StatefulWidget {
Stream({Key key, this.user}) : super(key: key);
final User user;
@override
_StreamState createState() => new _StreamState(
user: user
);
}
class _StreamState extends State<Stream> {
_StreamState({this.user});
final User user;
Firestore _firestore = Firestore.instance;
List<DocumentSnapshot> _posts = [];
bool _loadingPosts = true;
int _per_page = 30;
DocumentSnapshot _lastPosts;
ScrollController _scrollController = ScrollController();
bool _gettingMorePosts = false;
bool _morePostsAvailable = true;
_getPosts() async {
Query q = _firestore
.collection('posts')
.document(user.user_id)
.collection('posts')
.orderBy("timePosted", descending: true)
.limit(_per_page);
setState(() {
_loadingPosts = true;
});
QuerySnapshot querySnapshot = await q.getDocuments();
_posts = querySnapshot.documents;
if (_posts.length == 0) {
setState(() {
_loadingPosts = false;
});
}
else {
_lastPosts = querySnapshot.documents[querySnapshot.documents.length - 1];
setState(() {
_loadingPosts = false;
});
}
}
_getMorePosts() async {
if (_morePostsAvailable == false) {
return;
}
if (_gettingMorePosts == true) {
return;
}
if (_posts.length == 0) {
return;
}
_gettingMorePosts = true;
Query q = _firestore
.collection('posts')
.document(user.user_id)
.collection('posts')
.orderBy("timePosted", descending: true)
.startAfter([_lastPosts.data['timePosted']]).limit(_per_page);
QuerySnapshot querySnapshot = await q.getDocuments();
if (querySnapshot.documents.length == 0) {
_morePostsAvailable = false;
}
if(querySnapshot.documents.length > 0) {
_lastPosts = querySnapshot.documents[querySnapshot.documents.length - 1];
}
_posts.addAll(querySnapshot.documents);
setState(() {});
_gettingMorePosts = false;
}
@override
void initState() {
super.initState();
_getPosts();
_scrollController.addListener(() {
double maxScroll = _scrollController.position.maxScrollExtent;
double currentScroll = _scrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.25;
if (maxScroll - currentScroll < delta) {
_getMorePosts();
}
});
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
new Expanded(
child: _loadingPosts == true
? Container(
child: Center(
child: Text(" "),
),
)
: Container(
child: Center(
child: _posts.length == 0
? Center(
child: Text("Follow friends", style: TextStyle(fontSize: 15),),
)
: ListView.builder(
key: widget.key,
controller: _scrollController,
itemCount: _posts.length,
itemBuilder: (BuildContext ctx, int index) {
return new Widget(
//paramenters to build the post widget here
);
}),
),
),
),
],
);
}
需要注意的一件事是,由于我不想返回所有页面(由于Firestore花费了很多帖子),因此创建了构建逻辑,以便在滚动时加载更多的帖子。我意识到这可能会影响它。
答案 0 :(得分:1)
简短答案:
您需要像这样向ListView.builder
提供密钥:
ListView.builder(
key: PageStorageKey("any_text_here"),
// ...
)
长答案:
您可以看到,当您从屏幕2返回到屏幕1时,项目30仍停留在顶部。
对不起,由于所使用变量的可用性有限,因此很难再现代码。我创建了一个简单的示例来演示您要查找的内容。
完整代码:
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView.builder(
key: PageStorageKey("any_text_here"), // this is the key you need
itemCount: 50,
itemBuilder: (_, i) {
return ListTile(
title: Text("Item ${i}"),
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => DetailPage(index: i))),
);
},
),
);
}
}
class DetailPage extends StatefulWidget {
final int index;
const DetailPage({Key key, this.index}) : super(key: key);
@override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text(
"You clicked ${widget.index}",
style: Theme.of(context).textTheme.headline,
),
),
);
}
}
答案 1 :(得分:0)
这种键有效:
key: PageStorageKey('Your Key Name'),