我正在做与此视频类似的事情:https://youtu.be/fpqHUp4Sag0
使用以下代码生成列表视图,但是以这种方式使用控制器时,元素位于列表视图的顶部,我需要将其居中
Widget _buildLyric() {
return ListView.builder(
itemBuilder: (BuildContext context, int index) => _buildPhrase(lyric[index]),
itemCount: lyric.length,
itemExtent: 90.0,
controller: _scrollController,
);
}
void goToNext() {
i += 1;
if (i == lyric.length - 1) {
setState(() {
finishedSync = true;
});
}
syncLyric.addPhrase(
lyric[i], playerController.value.position.inMilliseconds);
_scrollController.animateTo(i*90.0,
curve: Curves.ease, duration: new Duration(milliseconds: 300));
}
答案 0 :(得分:0)
您将必须做一些数学运算! (不是,不是Mathssssss)。
似乎您的goToNext()函数是在应用运行时而不是在构建时调用的。这使操作变得容易一些-您可以简单地使用context.size
。否则,您将不得不使用LayoutBuilder和maxHeight。
然后您可以将其一分为二,得到一半,然后添加/减去所需的内容以定位所需的位置(由于在示例中将高度指定为90,我假设您可以使用45得到你想要的东西。
下面是一个示例,您可以将其粘贴到文件中以运行:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(Wid());
class Wid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Scrolling by time"),
),
body: new Column(
children: <Widget>[
Expanded(child: Container()),
Container(
height: 300.0,
color: Colors.orange,
child: ScrollsByTime(
itemExtent: 90.0,
),
),
Expanded(child: Container()),
],
),
),
);
}
}
class ScrollsByTime extends StatefulWidget {
final double itemExtent;
const ScrollsByTime({Key key, @required this.itemExtent}) : super(key: key);
@override
ScrollsByTimeState createState() {
return new ScrollsByTimeState();
}
}
class ScrollsByTimeState extends State<ScrollsByTime> {
final ScrollController _scrollController = new ScrollController();
@override
void initState() {
super.initState();
Timer.periodic(Duration(seconds: 1), (timer) {
_scrollController.animateTo(
(widget.itemExtent * timer.tick) - context.size.height / 2.0 + widget.itemExtent / 2.0,
duration: Duration(milliseconds: 300),
curve: Curves.ease,
);
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, index) {
return Center(child: Text("Item $index"));
},
itemExtent: widget.itemExtent,
controller: _scrollController,
);
}
}
答案 1 :(得分:0)
使用center
和shrinkWrap: true
Center(
child: new ListView.builder(
shrinkWrap: true,
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return Text("Centered item");
},
),
);
答案 2 :(得分:0)
我有一个类似的问题,但是使用水平列表视图。您应该使用ScrollController和NotificationListener。当您收到endScroll事件时,应该计算偏移量,并使用滚动控制器animateTo方法来使您的项目居中。
class SwipeCalendarState extends State<SwipeCalendar> {
List<DateTime> dates = List();
ScrollController _controller;
final itemWidth = 100.0;
@override
void initState() {
_controller = ScrollController();
_controller.addListener(_scrollListener);
for (var i = 1; i < 365; i++) {
var date = DateTime.now().add(Duration(days: i));
dates.add(date);
}
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
height: 200,
child: Stack(
children: <Widget>[buildListView()],
),
);
}
void _onStartScroll(ScrollMetrics metrics) {
}
void _onUpdateScroll(ScrollMetrics metrics){
}
void _onEndScroll(ScrollMetrics metrics){
print("scroll before = ${metrics.extentBefore}");
print("scroll after = ${metrics.extentAfter}");
print("scroll inside = ${metrics.extentInside}");
var halfOfTheWidth = itemWidth/2;
var offsetOfItem = metrics.extentBefore%itemWidth;
if (offsetOfItem < halfOfTheWidth) {
final offset = metrics.extentBefore - offsetOfItem;
print("offsetOfItem = ${offsetOfItem} offset = ${offset}");
Future.delayed(Duration(milliseconds: 50), (){
_controller.animateTo(offset, duration: Duration(milliseconds: 100), curve: Curves.linear);
});
} else if (offsetOfItem > halfOfTheWidth){
final offset = metrics.extentBefore + offsetOfItem;
print("offsetOfItem = ${offsetOfItem} offset = ${offset}");
Future.delayed(Duration(milliseconds: 50), (){
_controller.animateTo(offset, duration: Duration(milliseconds: 100), curve: Curves.linear);
});
}
}
Widget buildListView() {
return NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollStartNotification) {
_onStartScroll(scrollNotification.metrics);
} else if (scrollNotification is ScrollUpdateNotification) {
_onUpdateScroll(scrollNotification.metrics);
} else if (scrollNotification is ScrollEndNotification) {
_onEndScroll(scrollNotification.metrics);
}
},
child: ListView.builder(
itemCount: dates.length,
controller: _controller,
scrollDirection: Axis.horizontal,
itemBuilder: (context, i) {
var item = dates[i];
return Container(
height: 100,
width: itemWidth,
child: Center(
child: Text("${item.day}.${item.month}.${item.year}"),
),
);
}),
);
}
}
答案 3 :(得分:0)
IMO,您发布的链接有一些类似动画的轮子。 Flutter使用ListWheelScrollView提供了这种类型的动画,其余的操作可以通过动画的淡入和ScrollController的字体粗细更改来实现。