【问题标题】:how to sync scroll of singlechildscrollview and listview flutter?如何同步单子滚动视图和列表视图颤动的滚动?
【发布时间】:2019-03-20 15:10:03
【问题描述】:

singlechildscrollview 和 listview 的滚动如何结合?我正在尝试创建一个布局,其中有一个包含列的单子滚动视图,该列包含一些小部件和一个列表视图。如何结合滚动视图的滚动控制器和列表视图。 (即,我希望列表视图仅在其他小部件滚动并退出显示时滚动,并且仅在列表视图到达顶部时再次显示。)例如:在 instagram 应用程序中,您拥有像userimage、username、followers count、following count 等,然后有一个列表视图列出用户的帖子。卷轴已连接。我如何做到这一点???

我想要什么

我之前的代码

在实施 Andrey Turkovsky 的代码之后

【问题讨论】:

  • 您不想创建一个 listView,其中包含带有小部件的列,然后是您的列表项

标签: listview flutter


【解决方案1】:

当嵌套列表视图达到顶部时,我可以编写滚动父级的解决方案。这是我的一部分代码 - 我有包含 2 个元素的 ListView。第二个是另一个 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: ...,
      );
    }
  }

UPD 添加了使用流更改子滚动物理的解决方案

【讨论】:

  • 非常感谢您的回复但是我是新来的,我很难理解您的示例。能否请您详细说明。 (ScrollCallback、CommonScaffoldState 与 TickerProviderStateMixin、CommonListState)
  • ScrollCallback - 只是接受一个双参数(位置)的函数的别名,with TickerProviderStateMixin - 对于不同的动画控制器是必需的,但我认为你可以删除它(我只过去了必要的部分我的代码)。还有CommonListState - 对不起,我错过了 - 这是我的抽象类,但你可以使用普通的State
  • 请查看 gifs @Andrey Turkovsky
  • 现在获取您的解决方案 - 我已经更新了代码。将 widgetKey 添加到子列表视图上方的列中。我想你会理解另一个
【解决方案2】:

我构建我的 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
        },
    ),

然后我构建我的“TileWidget”,如下所示:

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(),
      ],
    );
  }
}

这不是很漂亮。但它很简单,而且很有效。

【讨论】:

    【解决方案3】:

    这可能有点晚了,但您可以像这样将 NeverScrollableScrollPhysics() 添加到 ListView 的物理参数中:

    Widget buildLoadedWidget(CarouselCardsLoaded state) {
    return ListView.builder(
      shrinkWrap: true,
      physics: NeverScrollableScrollPhysics(),
      itemBuilder: (context, i) {
        return GestureDetector(
          onTap: () async {
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-08
      • 2020-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多