Scrollable component

We need to use a sliding component when Flutter displays Overflow errors if the component content exceeds the current display viewport without special treatment.

A Scrollbar is a Material style scroll indicator (Scrollbar). To add a Scrollbar to a scrollable component, simply make the Scrollbar any parent component of the scrollable component and add child controls to it via child

SingleChildScrollView

A SingleChildScrollView is similar to an Android ScrollView in that it can only accept one child component. This is usually used when a control is very large, but not too much larger than the screen, the main properties are

  • scrollDirection: Scroll direction. The default is vertical,Axis. Vertical
  • reverse: Yes or no

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Scrollbar(
          child: SingleChildScrollView(
            child: Container(
              height: 2000,
              alignment: Alignment.center,
              color: Colors.yellow,
              child: Text("Hello World"),),),)); }}Copy the code

Let’s change direction

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Scrollbar(
          child: SingleChildScrollView(
            ///Rolling direction
            scrollDirection: Axis.horizontal,
            child: Container(
              width: 2000,
              height: 200,
              alignment: Alignment.center,
              color: Colors.yellow,
              child: Text("Hello World"),),),)); }}Copy the code

ListView

Based on using

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: ListView.builder(
            / / item number
            itemCount: 50.// The width or height of the item, depending on the sliding direction
            itemExtent: 50.// Item constructor
            itemBuilder: (BuildContext context, int index) {
              return ListTile(title: Text("$index")); })); }}Copy the code

Add fixed headers

What if we want to show off with a fixed head?

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Column(
          children: [
            ListTile(
              title: Text("Fixed head"),
            ),
            ListView.builder(
                / / item number
                itemCount: 50.// The width or height of the item, depending on the sliding direction
                itemExtent: 50.// Item constructor
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(title: Text("$index")); })])); }}Copy the code

After we write this, we find that the runtime will report an error

Error caught by rendering library, thrown during performResize()。 Vertical viewport was given unbounded height …

It basically means we need to specify a height, but we want the list to fill the screen. How do we do that? One is to dynamically calculate, remove the status bar, navigation bar, ListTile height, the other is to useFlexRecommend the latter one

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Column(
          children: [
            ListTile(
              title: Text("Fixed head"),
            ),
            Expanded(
                child: ListView.builder(
                    / / item number
                    itemCount: 50.// The width or height of the item, depending on the sliding direction
                    itemExtent: 50.// Item constructor
                    itemBuilder: (BuildContext context, int index) {
                      return ListTile(title: Text("$index")); })),])); }}Copy the code

Add a dividing line

This is where you need to use ListView.Separated

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    // Underline widgets are predefined for reuse.
    Widget divider1 = Divider(color: Colors.blue);
    Widget divider2 = Divider(color: Colors.red);

    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Column(
          children: [
            ListTile(
              title: Text("Fixed head"),
            ),
            Expanded(
                child: ListView.separated(
              / / item number
              itemCount: 50.// Item constructor
              itemBuilder: (BuildContext context, int index) {
                return ListTile(title: Text("$index"));
              },
              // The splitter constructor
              separatorBuilder: (BuildContext context, int index) {
                return index % 2= =0? divider1 : divider2; })),])); }}Copy the code

GridView

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: GridView(
        // Control the child widgets
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          // The number of children on the horizontal axis
          crossAxisCount: 3.// The ratio of the length of the child to the length of the main axis
          childAspectRatio: 1.// Spacing of child elements in the horizontal direction
          crossAxisSpacing: 20.// The spacing in the main axis direction
          mainAxisSpacing: 20,
        ),
        children: [
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("1"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("2"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("3"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("4"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("5"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("6"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("Seven"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("8"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("9"() [() [() [() }}Copy the code

Gridview.count can be used instead

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: GridView.count(
        // The number of children on the horizontal axis
        crossAxisCount: 3.// The ratio of the length of the child to the length of the main axis
        childAspectRatio: 1.// Spacing of child elements in the horizontal direction
        crossAxisSpacing: 20.// The spacing in the main axis direction
        mainAxisSpacing: 20,
        children: [
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("1"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("2"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("3"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("4"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("5"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("6"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("Seven"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("8"),
          ),
          Container(
            alignment: Alignment.center,
            color: Colors.red,
            child: Text("9"() [() [() [() }}Copy the code

CustomScrollView

If we want to have multiple slippable components on a page with uniform slippability, we need to use the CustomScrollView implementation

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: CustomScrollView(
        slivers: [
          //grid
          SliverGrid(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 3,
              mainAxisSpacing: 10.0,
              crossAxisSpacing: 10.0,
              childAspectRatio: 4.0,
            ),
            delegate: new SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return new Container(
                  alignment: Alignment.center,
                  color: Colors.blue,
                  child: new Text('grid item $index')); }, childCount:20,),),//List
          SliverFixedExtentList(
            itemExtent: 50.0,
            delegate: new SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                // Create a list item
                return new Container(
                  alignment: Alignment.center,
                  color: Colors.lightGreenAccent,
                  child: new Text('list item $index')); }, childCount:50,),),),),); }}Copy the code

Sliding to monitor

Using ScrollController

  • offset: Current scroll position of the scrollable component.
  • jumpTo(double offset),animateTo(double offset,...): These two methods are used to jump to a specified location. They differ in that the latter performs an animation while the former does not.

class _MyHomePageState extends State<MyHomePage> {
  ScrollController _scrollController = ScrollController();

  // Whether to display FloatButton
  bool showFloatButton = false;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(() {
      print(_scrollController.offset);
      // Determine the sliding distance
      if (_scrollController.offset < 200 && showFloatButton) {
        setState(() {
          showFloatButton = false;
        });
      } else if (_scrollController.offset >= 200 && showFloatButton == false) {
        setState(() {
          showFloatButton = true; }); }}); }@override
  void dispose() {
    // To avoid memory leaks, call _controller.dispose
    _scrollController.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView.builder(
          controller: _scrollController,
          / / item number
          itemCount: 50.// The width or height of the item, depending on the sliding direction
          itemExtent: 50.// Item constructor
          itemBuilder: (BuildContext context, int index) {
            return ListTile(title: Text("$index")); }), floatingActionButton: ! showFloatButton ?null
          : FloatingActionButton(
              child: Icon(Icons.arrow_upward),
              onPressed: () {
                // Execute the animation when you return to the top
                _scrollController.animateTo(0.0,
                    duration: Duration(milliseconds: 200), curve: Curves.ease); },),); }}Copy the code