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;
}
}
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.
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.
A scroll controller creates a [ScrollPosition] to manage the state-specific to an individual [Scrollable] widget.
You can assign a GlobalKey to the item you want to scroll to and make use of ScrollPosition.
You can with using this:
final dataKey = new GlobalKey();
key: dataKey
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With