How can I make a scrollable wrapping view with Flutter?

后端 未结 2 781
独厮守ぢ
独厮守ぢ 2021-02-15 11:26

I want to display a finite number of items and wrap when the user scrolls in either direction. How do I do this?

2条回答
  •  独厮守ぢ
    2021-02-15 12:02

    You can't easily solve this with an infinite-length ListView.builder because it only goes in one direction. If you want to wrap in both directions, it is possible to simulate bidirectional wrapping with a Stack of two viewports going in opposite directions.

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(new MaterialApp(
        home: new HomePage(),
      ));
    }
    
    class HomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('Wrapping List View'),
          ),
          body: new WrappingListView.builder(
            itemCount: 10,
            itemBuilder: (BuildContext context, int index) {
              return new Card(
                child: new Container(
                  height: 50.0,
                  color: Colors.blue.withOpacity(index / 10),
                  child: new Center(
                    child: new Text('Card $index')
                  ),
                ),
              );
            },
          ),
        );
      }
    }
    
    class WrappingListView extends StatefulWidget {
    
      factory WrappingListView({ Key key, List children }) {
        return new WrappingListView.builder(
          itemCount: children.length,
          itemBuilder: (BuildContext context, int index) {
            return children[index % children.length];
          },
        );
      }
    
      WrappingListView.builder({ Key key, this.itemBuilder, this.itemCount })
        : super(key: key);
    
      final int itemCount;
      final IndexedWidgetBuilder itemBuilder;
    
      WrappingListViewState createState() => new WrappingListViewState();
    }
    
    class UnboundedScrollPosition extends ScrollPositionWithSingleContext {
      UnboundedScrollPosition({
        ScrollPhysics physics,
        ScrollContext context,
        ScrollPosition oldPosition,
      }) : super(physics: physics, context: context, oldPosition: oldPosition);
    
      @override
      double get minScrollExtent => double.negativeInfinity;
    }
    
    class UnboundedScrollController extends ScrollController {
      @override
      UnboundedScrollPosition createScrollPosition(
        ScrollPhysics physics,
        ScrollContext context,
        ScrollPosition oldPosition,
      ) {
        return new UnboundedScrollPosition(
          physics: physics,
          context: context,
          oldPosition: oldPosition,
        );
      }
    }
    
    class WrappingListViewState extends State {
      UnboundedScrollController _controller = new UnboundedScrollController();
      UnboundedScrollController _negativeController = new UnboundedScrollController();
    
      @override
      void initState() {
        _controller.addListener(() {
          _negativeController.jumpTo(
            -_negativeController.position.extentInside -
            _controller.position.pixels,
          );
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return new Stack(
          children: [
            new CustomScrollView(
              physics: new AlwaysScrollableScrollPhysics(),
              controller: _negativeController,
              reverse: true,
              slivers: [
                new SliverList(
                  delegate: new SliverChildBuilderDelegate(
                    (BuildContext context, int index) {
                      return widget.itemBuilder(
                        context,
                        (widget.itemCount - 1 - index) % widget.itemCount,
                      );
                    }
                  ),
                ),
              ],
            ),
            new ListView.builder(
              controller: _controller,
              itemBuilder: (BuildContext context, int index) {
                return widget.itemBuilder(context, index % widget.itemCount);
              },
            ),
          ],
        );
      }
    }
    

提交回复
热议问题