Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a scrollable wrapping view with Flutter?

Tags:

flutter

dart

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

like image 625
Collin Jackson Avatar asked Jun 10 '17 00:06

Collin Jackson


People also ask

How do you add scrolls down in flutter?

By default, scrollable widgets in Flutter don't show a scrollbar. To add a scrollbar to a ScrollView, wrap the scroll view widget in a Scrollbar widget. Using this widget we can scroll a widget. The scrollbar allows the user to jump into the particular points and also shows how far the user reaches.


2 Answers

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.

screenshot

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<Widget> 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<WrappingListView> {
  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: <Widget>[
        new CustomScrollView(
          physics: new AlwaysScrollableScrollPhysics(),
          controller: _negativeController,
          reverse: true,
          slivers: <Widget>[
            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);
          },
        ),
      ],
    );
  }
}
like image 150
Collin Jackson Avatar answered Oct 19 '22 20:10

Collin Jackson


As of December 2018 you can use this (with a suitable builder): https://pub.dartlang.org/packages/infinite_listview

Or this: https://pub.dev/packages/indexed_list_view

like image 36
MarcG Avatar answered Oct 19 '22 20:10

MarcG