[英]How to scroll to the next item in the ListView
我正在嘗試為下一個元素制作一個可滾動的 ListView,以便它始終位於頁面的開頭(或中心)(如在 PageView 中)
我的問題是慣性,滾動后元素向后移動。
如何在沒有慣性的情況下實現項目的行為?
代碼:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<ScrollController> _horizontalControllers;
ScrollController _verticalController;
var _itemCountHorizontal = 15;
bool _inProgress;
Orientation get isPortrait => MediaQuery.of(context).orientation;
double get _height => MediaQuery.of(context).size.height;
double get _width => MediaQuery.of(context).size.width;
double get horizontalPadding {
double _padd;
if (isPortrait == Orientation.portrait) {
_padd = _width * 0.01;
} else {
_padd = _width * 0.01;
}
return _padd;
}
double get verticalPadding {
double _padd;
if (isPortrait == Orientation.portrait) {
_padd = cardHeight * 0.005;
} else {
_padd = (_height - cardHeight) / 2;
}
return _padd;
}
double get cardHeight {
double cardH;
if (isPortrait == Orientation.portrait) {
cardH = cardWidth * 1.7;
} else {
cardH = _height * 0.9;
}
return cardH;
}
double get cardWidth {
var cardW = _width * 0.99;
if (cardW > _height / 1.7) {
cardW = _height / 1.77;
}
return cardW;
}
@override
void initState() {
_horizontalControllers = [
ScrollController(),
ScrollController(),
ScrollController(),
ScrollController(),
ScrollController(),
];
_verticalController = ScrollController();
_inProgress = false;
super.initState();
}
@override
void dispose() {
_horizontalControllers.forEach((element) {
element.dispose();
});
_verticalController.dispose();
super.dispose();
}
void _onEndScrollVertical(ScrollMetrics metrics) {
print("scroll before = ${metrics.extentBefore}");
print("scroll after = ${metrics.extentAfter}");
print("scroll inside = ${metrics.extentInside}");
print("index = ${metrics.axisDirection}");
print("item HEIGHT => $cardHeight");
final topPadd = MediaQuery.of(context).padding.top;
print('TOPPPPPPPPPP $topPadd');
/* int point = metrics.extentAfter ~/ (_height - topPadd);
var offset = (_height - topPadd) * point;
_inProgress = true;
Future.delayed(Duration(milliseconds: 100), () {
_verticalController.animateTo(offset,
duration: Duration(milliseconds: 1000), curve: Curves.fastOutSlowIn);
});
_inProgress = false;
*/
var halfOfTheHeight = cardHeight / 2;
var offsetOfItem = metrics.extentBefore % cardHeight;
if (offsetOfItem < halfOfTheHeight) {
final offset = metrics.extentBefore - offsetOfItem;
print("offsetOfItem1 = $offsetOfItem offset = $offset");
Future.delayed(Duration(milliseconds: 50), () {
_verticalController.animateTo(offset,
duration: Duration(milliseconds: 1000),
curve: Curves.fastOutSlowIn);
});
} else if (offsetOfItem > halfOfTheHeight) {
final offset = metrics.extentBefore + offsetOfItem;
print("offsetOfItem2 = $offsetOfItem offset = $offset");
Future.delayed(Duration(milliseconds: 50), () {
_verticalController.animateTo(offset,
duration: Duration(milliseconds: 1000),
curve: Curves.fastOutSlowIn);
});
}
}
void _onEndScrollHorizontal(ScrollMetrics metrics, int index) {
print("scroll before = ${metrics.extentBefore}");
print("scroll after = ${metrics.extentAfter}");
print("scroll inside = ${metrics.extentInside}");
print("item WIDTH => $cardWidth");
var halfOfTheWidth = _width / 2;
var offsetOfItem = metrics.extentBefore % _width;
if (offsetOfItem < halfOfTheWidth) {
final offset = metrics.extentBefore - offsetOfItem;
print("offsetOfItem1 = $offsetOfItem offset = $offset");
_inProgress = true;
Future.delayed(Duration(milliseconds: 10), () {
_horizontalControllers[index].animateTo(offset,
duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
});
_inProgress = false;
} else if (offsetOfItem > halfOfTheWidth) {
_inProgress = true;
final offset = metrics.extentBefore + offsetOfItem;
print("offsetOfItem2 = $offsetOfItem offset = $offset");
Future.delayed(Duration(milliseconds: 10), () {
_horizontalControllers[index].animateTo(offset,
duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
});
_inProgress = false;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollEndNotification &&
scrollNotification.depth == 0) {
if (!_inProgress) {
print('ScrollEndNotification ===> $scrollNotification');
_onEndScrollVertical(scrollNotification.metrics);
}
}
return null;
},
child: buildListViewVertical(),
),
),
);
}
Widget buildListViewVertical() {
return ListView.builder(
itemCount: _itemCountHorizontal,
itemExtent: cardHeight,
controller: _verticalController,
itemBuilder: (BuildContext context, int index) {
return NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollEndNotification &&
scrollNotification.depth == 0) {
print('ScrollEndNotification ===> $scrollNotification');
_onEndScrollHorizontal(scrollNotification.metrics, index);
}
return null;
},
child: buildListViewHorizontal(index));
},
);
}
Widget buildListViewHorizontal(int index) {
return ListView.builder(
controller: _horizontalControllers[index],
physics: ClampingScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: _itemCountHorizontal + 1,
itemBuilder: (BuildContext context, int index) =>
index < _itemCountHorizontal
? Padding(
padding: EdgeInsets.only(
left: horizontalPadding,
right: horizontalPadding,
top: verticalPadding,
bottom: verticalPadding,
),
child: Container(height: 340, width: 200, color: Colors.red),
)
: SizedBox(
width: 50,
),
);
}
}
更新:
我將 CustomScrollPhysics() 添加到 ListView,該解決方案消除了反向運動的慣性。 然而,從索引 0 及以上移動時,慣性仍然存在......代碼:
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
class CustomScrollPhysics extends ScrollPhysics {
const CustomScrollPhysics({ScrollPhysics parent}) : super(parent: parent);
@override
SpringDescription get spring => SpringDescription(damping: 0.1);
@override
CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
return CustomScrollPhysics(parent: buildParent(ancestor));
}
}
您可以使用 DraggableScrollableSheet 和 SingleChildScrollView 小部件
首先,您需要將小部件更改為 statefullwidget,然后您需要使用 Global 鍵滾動到您想要的位置。 以及您要滾動到“小部件前”的位置。 必須有名字。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.