如何同步singlechildscrollview和listview颤振的滚动?
如何组合singlechildscrollview和listview的滚动?我试图创建一个布局,其中有一个singlechildscrollview,其中包含包装一些小部件的列和一个listview。如何组合滚动视图和列表视图的滚动控制器。(也就是说,我希望listview仅在其他窗口小部件被滚动出屏幕时滚动,并且仅在listview到达顶部时再次显示。)例如:在instagram应用程序中,您拥有userimage、username、followers count、following count等窗口小部件,然后有一个列出用户帖子的listview。卷轴已连接。我如何做到这一点 我想要什么 我以前的代码 在实现Andrey Turkovsky的代码之后如何同步singlechildscrollview和listview颤振的滚动?,listview,flutter,Listview,Flutter,如何组合singlechildscrollview和listview的滚动?我试图创建一个布局,其中有一个singlechildscrollview,其中包含包装一些小部件的列和一个listview。如何组合滚动视图和列表视图的滚动控制器。(也就是说,我希望listview仅在其他窗口小部件被滚动出屏幕时滚动,并且仅在listview到达顶部时再次显示。)例如:在instagram应用程序中,您拥有userimage、username、followers count、following coun
当嵌套listview到达顶部时,我可以编写滚动父级的解决方案。这是me代码的一部分-我有一个包含2个元素的ListView。第二个是另一个列表视图
class _ConferenceScaffoldState extends CommonScaffoldState<ConferenceScaffold> {
final ScrollController controller = ScrollController();
final GlobalKey widgetKey = GlobalKey();
/* widgetKey is for widget in buildHeaderRow() */
StreamController<bool> _streamController = StreamController<bool>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(conference_title),
centerTitle: true,
),
body: getBody(),
);
}
Widget getBody() {
controller.addListener((){
if (widgetKey.currentContext != null) {
double height = widgetKey.currentContext.size.height;
_streamController.add(controller.offset >= height);
}
});
return ListView(
controller: controller,
children: <Widget>[buildHeaderRow(), buildPagerRow()],
);
}
Widget buildPagerRow() => _EventSpeakerPager(scrollCallback, _streamController.stream);
scrollCallback(double position) => controller.position.jumpTo(controller.position.pixels - position);
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
typedef ScrollCallback = void Function(double position);
class _EventSpeakerPager extends StatefulWidget {
_EventSpeakerPager(this.callback, this.stream);
final ScrollCallback callback;
final Stream<bool> stream;
@override
State<StatefulWidget> createState() => _EventSpeakerPagerState();
}
class _EventSpeakerPagerState extends State<_EventSpeakerPager> {
final GlobalKey tabKey = GlobalKey();
bool isChildScrollEnabled = false;
@override
void initState() {
super.initState();
widget.stream.distinct().listen((bool data) {
setState(() {
isChildScrollEnabled = data;
});
});
}
@override
Widget build(BuildContext context) {
ListView eventList = ListView.builder(
physics: isChildScrollEnabled ? AlwaysScrollableScrollPhysics() : NeverScrollableScrollPhysics(),
controller: ScrollController(),
itemBuilder: (buildContext, position) {
if (position.isOdd) return CommonDivider();
return buildEventRow(getEventList()[position ~/ 2], false, null);
},
itemCount: getEventList().length * 2,
);
return Listener(
onPointerMove: (event) {
double pixels = eventList.controller.position.pixels;
if (event.delta.dy > 0.0 && pixels == 0.0) widget.callback(event.delta.dy);
},
child: ...,
);
}
}
class\u ConferenceScaffoldState扩展CommonCaffoldState{
最终ScrollController=ScrollController();
最终GlobalKey-widgetKey=GlobalKey();
/*widgetKey用于buildHeaderRow()中的小部件*/
StreamController _StreamController=StreamController();
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(会议标题),
标题:对,
),
body:getBody(),
);
}
小部件getBody(){
controller.addListener(){
if(widgetKey.currentContext!=null){
双重高度=widgetKey.currentContext.size.height;
_streamController.add(controller.offset>=高度);
}
});
返回列表视图(
控制器:控制器,
子项:[buildHeaderRow(),buildPagerRow()],
);
}
Widget buildPagerRow()=>\u eventSpeakerPage(scrollCallback,\u streamController.stream);
scrollCallback(双位置)=>controller.position.jumpTo(controller.position.pixels-position);
@凌驾
无效处置(){
controller.dispose();
super.dispose();
}
}
typedef ScrollCallback=无效函数(双位置);
类_EventSpeakerPager扩展StatefulWidget{
_EventSpeakerPage(this.callback,this.stream);
最终卷轴回调;
最终河流;
@凌驾
State createState()=>\u EventSpeakerPagerState();
}
类_EventSpeakerPagerState扩展状态{
最终的GlobalKey tabKey=GlobalKey();
bool isChildScrollEnabled=false;
@凌驾
void initState(){
super.initState();
widget.stream.distinct().listen((bool数据){
设置状态(){
IsChildScrolEnabled=数据;
});
});
}
@凌驾
小部件构建(构建上下文){
ListView事件列表=ListView.builder(
物理:是否已禁用?始终滚动滚动滚动物理():从不滚动滚动滚动物理(),
控制器:ScrollController(),
itemBuilder:(构建上下文,位置){
if(position.isOdd)返回CommonDivider();
返回buildEventRow(getEventList()[position~/2],false,null);
},
itemCount:getEventList().length*2,
);
返回侦听器(
onPointerMove:(事件){
双像素=eventList.controller.position.pixels;
if(event.delta.dy>0.0&&pixels==0.0)widget.callback(event.delta.dy);
},
孩子:。。。,
);
}
}
UPD
添加了使用stream更改子对象滚动物理的解决方案我构建了我的Listview,如下所示:
List<String> myList = ["one", "two", "three", "four"]; //Just some example list data
ListView.builder(,
itemCount: myList.length,
itemBuilder: (BuildContext context, int index) {
return TileWidget(
myList[index],
index == 0, //this indicates that it is the first item
index == myList.length - 1); //this indicates that it is the last item
},
),
class TileWidget extends StatelessWidget {
TileWidget(this.tileData, this.isFirstItem, this.isLastItem,);
String tileData;
bool isFirstItem;
bool isLastItem;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
isFirstItem ? Text("this is a title") : Container(),
Text(tileData),
isLastItem ? Text("This is a footer") : Container(),
],
);
}
}
List myList=[“一”、“二”、“三”、“四”]//只是一些示例列表数据
ListView.builder(,
itemCount:myList.length,
itemBuilder:(构建上下文,int索引){
返回平铺边(
myList[索引],
index==0,//这表示它是第一项
index==myList.length-1);//这表示它是最后一项
},
),
然后我构建我的“TileWidget”,如下所示:
List<String> myList = ["one", "two", "three", "four"]; //Just some example list data
ListView.builder(,
itemCount: myList.length,
itemBuilder: (BuildContext context, int index) {
return TileWidget(
myList[index],
index == 0, //this indicates that it is the first item
index == myList.length - 1); //this indicates that it is the last item
},
),
class TileWidget extends StatelessWidget {
TileWidget(this.tileData, this.isFirstItem, this.isLastItem,);
String tileData;
bool isFirstItem;
bool isLastItem;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
isFirstItem ? Text("this is a title") : Container(),
Text(tileData),
isLastItem ? Text("This is a footer") : Container(),
],
);
}
}
class TileWidget扩展了无状态小部件{
TileWidget(this.tileData,this.isFirstItem,this.isLastItem,);
线状瓦氏体;
布尔是第一项;
布尔群岛;
@凌驾
小部件构建(构建上下文){
返回列(
儿童:[
isFirstItem?文本(“这是一个标题”):Container(),
文本(tileData),
isLastItem?Text(“这是一个页脚”):Container(),
],
);
}
}
不太好看。但是它很简单,而且可以工作。这可能有点晚了,但是您可以像这样将NeverScrollableScrollPhysics()添加到ListView的物理参数中:
Widget buildLoadedWidget(CarouselCardsLoaded state) {
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, i) {
return GestureDetector(
onTap: () async {
你不想创建一个列表视图,其中包含带有小部件的列,然后是你的列表项吗?非常感谢你的回答,但是我是一个新手,我发现很难理解你的示例。你能详细说明一下吗。(ScrollCallback,CommonCaffoldState with TickerProviderStateMixin,CommonListState)
ScrollCallback
-仅是带有一个双参数(位置)的函数的别名,with TickerProviderStateMixin
-这对于不同的动画控制器是必要的,但我认为您可以删除它(我只跳过了代码中必要的一部分). 和CommonListState
-抱歉,我错过了它-这是我的抽象类,但是你可以使用普通的State
请检查gifs@Andrey turkovsky,现在获取你的解决方案-我已经更新了代码。将widgetKey添加到子listview上方的列中。我想你会理解另一个