ListView
항목 수가 동적으로 변경 될 수 있는 스크롤 가능 이 있습니다. 새 항목이 목록 끝에 추가 될 때마다 프로그래밍 방식으로 ListView
끝까지 스크롤하고 싶습니다 . (예 : 마지막에 새 메시지를 추가 할 수있는 채팅 메시지 목록과 같은 것)
내 생각 엔 객체 ScrollController
에서 를 만들고 생성자에 State
수동으로 전달해야 ListView
나중에 컨트롤러에서 animateTo()
/ jumpTo()
메서드를 호출 할 수 있습니다 . 그러나 최대 스크롤 오프셋을 쉽게 결정할 수 없기 때문에 단순히 scrollToEnd()
일종의 작업을 수행하는 것은 불가능 해 보입니다 (단순히 통과 0.0
하여 초기 위치로 스크롤 할 수 있음).
이것을 달성하는 쉬운 방법이 있습니까?
뷰포트에 reverse: true
맞는 항목 수가 적을 때 항목이 상단에 정렬되기를 원하기 때문에 사용 은 나에게 완벽한 솔루션이 아닙니다 ListView
.
답변
당신은 수축 포장 사용하는 경우 ListView
에 reverse: true
당신이 원하는 것을 할 것입니다 0.0로 스크롤합니다.
import 'dart:collection';
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Example',
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Widget> _messages = <Widget>[new Text('hello'), new Text('world')];
ScrollController _scrollController = new ScrollController();
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Container(
decoration: new BoxDecoration(backgroundColor: Colors.blueGrey.shade100),
width: 100.0,
height: 100.0,
child: new Column(
children: [
new Flexible(
child: new ListView(
controller: _scrollController,
reverse: true,
shrinkWrap: true,
children: new UnmodifiableListView(_messages),
),
),
],
),
),
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
onPressed: () {
setState(() {
_messages.insert(0, new Text("message ${_messages.length}"));
});
_scrollController.animateTo(
0.0,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
}
),
);
}
}
답변
사용 ScrollController.jumpTo()
또는ScrollController.animateTo()
이를 달성하기 위해 방법.
예:
final _controller = ScrollController();
@override
Widget build(BuildContext context) {
// After 1 second, it takes you to the bottom of the ListView
Timer(
Duration(seconds: 1),
() => _controller.jumpTo(_controller.position.maxScrollExtent),
);
return ListView.builder(
controller: _controller,
itemCount: 50,
itemBuilder: (_, __) => ListTile(title: Text('ListTile')),
);
}
부드러운 스크롤을 원하면 jumpTo
위의 사용 대신
_controller.animateTo(
_controller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
답변
listViewScrollController.animateTo(listViewScrollController.position.maxScrollExtent)
가장 간단한 방법입니다.
답변
완벽한 결과를 얻기 위해 Colin Jackson과 CopsOnRoad의 답변을 다음과 같이 결합했습니다.
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 500),
);
답변
스크롤 컨트롤러를 사용하여 목록의 맨 아래로 이동하는 데 너무 많은 문제가있어서 다른 접근 방식을 사용합니다.
목록을 맨 아래로 보내는 이벤트를 만드는 대신 반전 된 목록을 사용하도록 논리를 변경합니다.
그래서 매번 새 항목이있을 때마다 목록 맨 위에 삽입하여 만들었습니다.
// add new message at the begin of the list
list.insert(0, message);
// ...
// pull items from the database
list = await bean.getAllReversed(); // basically a method that applies a descendent order
// I remove the scroll controller
new Flexible(
child: new ListView.builder(
reverse: true,
key: new Key(model.count().toString()),
itemCount: model.count(),
itemBuilder: (context, i) => ChatItem.displayMessage(model.getItem(i))
),
),
답변
widgetBinding을 initstate에 두지 마십시오. 대신 데이터베이스에서 데이터를 가져 오는 메소드에 넣어야합니다. 예를 들면 이렇게요. initstate에 넣으면 목록보기에 scrollcontroller
첨부되지 않습니다.
Future<List<Message>> fetchMessage() async {
var res = await Api().getData("message");
var body = json.decode(res.body);
if (res.statusCode == 200) {
List<Message> messages = [];
var count=0;
for (var u in body) {
count++;
Message message = Message.fromJson(u);
messages.add(message);
}
WidgetsBinding.instance
.addPostFrameCallback((_){
if (_scrollController.hasClients) {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
}
});
return messages;
} else {
throw Exception('Failed to load album');
}
}
답변
StreamBuilder
내 데이터베이스에서 데이터를 가져 오기 위해 위젯을 사용할 때이 문제가 발생했습니다 . 나는 WidgetsBinding.instance.addPostFrameCallback
위젯의 build
방법 위에 올려 놓았고 끝까지 스크롤되지 않았습니다. 다음과 같이 수정했습니다.
...
StreamBuilder(
stream: ...,
builder: (BuildContext context, AsyncSnapshot snapshot) {
// Like this:
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_controller.hasClients) {
_controller.jumpTo(_controller.position.maxScrollExtent);
} else {
setState(() => null);
}
});
return PutYourListViewHere
}),
...
나도 시도했지만 _controller.animateTo
작동하지 않는 것 같습니다.