Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter how to scroll to a specific item position in SliverList?

I have a SliverList with SliverChildBuilderDelegate, my problem is that I cannot set ScrollController to SliverList because I want to control scrolling of my List, I am looking for scrolling to specific item in the list(which is very large) and in normal ListView this job is very easy and i am wonder why there is no controller property in SliverList like ListView?

Note : I know that CustomScrollView has controller property and I have tested but this will control the whole viewport not only the List

 @override
  Widget build(BuildContext context) {
    MainState m = Provider.of<MainState>(context, listen: false);
    return DefaultTabController(
      length: m.itemCategoryList.length,
      child: Scaffold(
          // appBar: _createAppBar(),
          body: Builder(builder: (context) => _createBody(context))),
    );
  }

  AppBar _createAppBar() {
    MainState m = Provider.of<MainState>(context);

    return AppBar(
      title: Text(
        m.selectedPartner.fullname,
        style: Theme.of(context).textTheme.display3,
      ),
      leading: IconButton(
        icon: Icon(Icons.arrow_back),
        onPressed: () {
          Navigator.pop(context);
        },
      ),
    );
  }

  _createBody(BuildContext context) {
    MainState m = Provider.of<MainState>(context);
    return CustomScrollView(
      slivers: <Widget>[
        SliverAppBar(
          titleSpacing: 0.0,
          elevation: 20.0,
          title: Container(
            decoration: BoxDecoration(color: Colors.black.withOpacity(0.3)),
            child: Column(
              children: <Widget>[
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: <Widget>[
                    IconButton(
                      icon: Icon(Icons.arrow_back),
                      onPressed: () {
                        Navigator.pop(context);
                      },
                    ),
                    Spacer(
                      flex: 2,
                    ),
                    IconButton(
                      icon: Icon(Icons.info),
                      onPressed: () {},
                    ),
                    IconButton(
                      icon: Icon(Icons.search),
                      onPressed: () {},
                    ),
                  ],
                ),
              ],
            ),
          ),
          centerTitle: false,
          automaticallyImplyLeading: false,
          pinned: true,
          bottom: PreferredSize(
            // Add this code
            preferredSize: Size.fromHeight(10.0), // Add this code
            child: Text(''), // Add this code
          ),
          expandedHeight: 250,
          flexibleSpace: FlexibleSpaceBar(
              centerTitle: true,
              collapseMode: CollapseMode.none,
              background: Stack(
                children: <Widget>[
                  Image.network(
                    m.selectedPartner.imagepath,
                    fit: BoxFit.cover,
                    height: 300.0,
                    width: MediaQuery.of(context).size.width,
                    color: Colors.black.withOpacity(0.6),
                    colorBlendMode: BlendMode.darken,
                  ),
                  Align(
                    alignment: Alignment.center,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Text(
                          m.selectedPartner.fullname,
                          style: Theme.of(context)
                              .textTheme
                              .headline
                              .copyWith(color: Colors.white),
                        ),
                        Text(
                          m.selectedPartner.categorytexts,
                          style: Theme.of(context)
                              .textTheme
                              .title
                              .copyWith(fontSize: 17.0, color: Colors.white),
                        ),
                      ],
                    ),
                  ),
                  Align(
                    alignment: Alignment.bottomCenter,
                    child: Container(
                      height: 30.0,
                      decoration: BoxDecoration(color: Colors.white),
                      child: Row(
                        children: <Widget>[
                          Text(
                              "Delivery time :" +
                                  m.selectedPartner.deliverytime.toString() +
                                  " mins",
                              style: Theme.of(context).textTheme.subtitle)
                        ],
                      ),
                    ),
                  )
                ],
              )),
        ),
        SliverPersistentHeader(
          delegate: _SliverAppBarDelegate(
            TabBar(
              isScrollable: true,
              labelColor: Colors.black87,
              unselectedLabelColor: Colors.black,
              tabs: m.itemCategoryList
                  .map((ele) => Tab(
                        text: ele.itemcategoryname,
                      ))
                  .toList(),
            ),
          ),
          pinned: true,
        ),
//=========I want to scroll to a specific position in this list
        GroupedSliverList(
            elements: m.itemList,
            groupBy: (ItemModel item) => item.itemcategory_id,
            groupSeparatorBuilder: (i, item) => _createGroupItem(i, item),
            itemBuilder: (_, item) => _createItem(item)),
      ],
    );
  }


  _createGroupItem(int categId, ItemModel item) {
    MainState m = Provider.of<MainState>(context, listen: false);
    ItemCategoryModel categModel =
        m.itemCategoryList.firstWhere((ele) => ele.id == categId);
    return Container(
      child: Text(
        categModel.itemcategoryname,
        style: Theme.of(context).textTheme.headline,
      ),
    );
  }

 

  _createItem(ItemModel item) {
    return Card(
      elevation: 3.0,
      child: Padding(
        padding: const EdgeInsets.all(10.0),
        child: Row(
          children: <Widget>[
            CircleAvatar(
              radius: 30.0,
              backgroundImage: NetworkImage(item.imagepath),
            ),
            SizedBox(
              width: 18.0,
            ),
            _createDetailColumn(item)
          ],
        ),
      ),
    );
  }

  _createDetailColumn(ItemModel item) {
    return Expanded(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Flexible(
              flex: 1,
              child: Row(
                children: <Widget>[
                  Expanded(
                    child: Text(
                      item.itemname,
                      style: Theme.of(context).textTheme.title,
                    ),
                  ),
                ],
              )),
          SizedBox(
            height: 5.0,
          ),
          Flexible(
            flex: 1,
            child: Row(
              children: <Widget>[
                Expanded(
                  child: Text(
                    item.description,
                    style: Theme.of(context).textTheme.subtitle,
                  ),
                ),
              ],
            ),
          ),
          SizedBox(
            height: 5.0,
          ),
          SizedBox(
            height: 8.0,
          ),
          Row(
            children: <Widget>[
              Container(
                decoration: BoxDecoration(
                    border: Border.all(color: Colors.green, width: 1.0),
                    borderRadius: BorderRadius.circular(10.0)),
                child: Padding(
                  padding: const EdgeInsets.all(6.0),
                  child: Text(item.price.toString() + " L.E.",
                      style: Theme.of(context)
                          .textTheme
                          .subtitle
                          .copyWith(color: Colors.green, fontSize: 16.0)),
                ),
              ),
            ],
          )
        ],
      ),
    );
  }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate(this._tabBar);

  final TabBar _tabBar;

  @override
  double get minExtent => _tabBar.preferredSize.height;
  @override
  double get maxExtent => _tabBar.preferredSize.height;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return new Container(
      color: Colors.yellow,
      child: _tabBar,
    );
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return false;
  }
}
like image 359
aym1781969 Avatar asked Mar 04 '20 14:03

aym1781969


People also ask

How do I scroll to a specific position in Flutter?

All you have to do is set Global Keys for your widgets and call Scrollable. ensureVisible on the key of your widget you want to scroll to. For this to work your ListView should be a finite List of objects. If you are using ListView.

How do I scroll to a specific position in ListView Flutter?

To scroll a Flutter ListView widget horizontally, set scrollDirection property of the ListView widget to Axis. horizontal. This arranges the items side by side horzontally.

What is widget we use in the Talk to scroll to specific position in list?

A scroll controller creates a [ScrollPosition] to manage the state-specific to an individual [Scrollable] widget.

Is there a way to automatically scroll to an element in ListView builder?

You can assign a GlobalKey to the item you want to scroll to and make use of ScrollPosition.


1 Answers

You can with using this:

  1. Create a global key for your specific item position like this final dataKey = new GlobalKey();
  2. Add to this specific position the key key: dataKey
  3. Add the command that will make the page scroll to your button Scrollable.ensureVisible(dataKey.currentContext)

This is the full code for scrolling to the last item:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Scroll To Index Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SilverAppBarExample(),
    );
  }
}



class SilverAppBarExample extends StatelessWidget {
  final dataKey = new GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        // width: MediaQuery.of(context).size.width,
        // height: MediaQuery.of(context).size.height,
        child: CustomScrollView(
          slivers: <Widget>[
            SliverAppBar(
              leading: IconButton(
                  icon: Icon(Icons.filter_1),
                  onPressed: () {
                    // Do something
                  }),
              expandedHeight: 220.0,
              floating: true,
              pinned: true,
              snap: true,
              elevation: 50,
              backgroundColor: Colors.pink,
              flexibleSpace: FlexibleSpaceBar(
                centerTitle: true,
                title: Text('Title',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 16.0,
                    )),
                background: Image.network(
                  'https://media-exp1.licdn.com/dms/image/C4D03AQEs7z0qHy2IWA/profile-displayphoto-shrink_400_400/0/1587196263121?e=1611792000&v=beta&t=bGjaklbEtTDYOFk5UvGLOTO5N3pSvIJtq6javEp32lU',
                  fit: BoxFit.cover,
                ),
              ),
            ),
            new SliverList(
              delegate: new SliverChildListDelegate([
                Column(
                  children: [
                    _buildList(50),
                    Card(
                      key: dataKey,
                      child: new Text("data\n\n\n\n\n\ndata"),
                    ),
                  ],
                ),
              ]),
            ),
          ],
        ),
      ),
      bottomNavigationBar: new RaisedButton(
        onPressed: () => Scrollable.ensureVisible(dataKey.currentContext),
        child: new Text("Scroll to data"),
      ),
    );
  }

  Widget _buildList(int count) {
    List<Widget> listItems = List();

    for (int i = 0; i < count; i++) {
      listItems.add(
        new Padding(
          padding: new EdgeInsets.all(20.0),
          child: new Text(
            'Item ${i.toString()}',
            style: new TextStyle(fontSize: 25.0),
          ),
        ),
      );
    }

    return Column(
      children: listItems,
    );
  }
}

the page before the scroll:

the page after the scroll:

like image 169
Mohamed Reda Avatar answered Sep 27 '22 17:09

Mohamed Reda