I'm using a Swiper package to achieve a carousel effect on my images.
I'm trying to update the current index of my Swiper by passing a callback function to it's child.
but when I try to call the function, it returns this " scrollcontroller not attached " error.
I've added a SwiperController but still the same.
Here is my code:
SwiperController swiperController;
#override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.black,
child: Swiper(
controller: swiperController,
index: _index,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext c, int i) {
return StoriesPerUser(
storiesList: widget.storiesList,
selectedIndex: i,
updateFunction: callBack,
);
},
itemCount: widget.storiesList.length,
loop: false,
duration: 1000,
));
}
callBack() {
setState(() {
_index++;
});
}
Please help.
ANSWER:
If any of you guys want to use this package, and if you want a feature similar to mine, instead of updating the index, just use the one of the methods of SwiperController which is next().
this solved my problem:
callBack() {
setState(() {
swiperController.next();
});
}
Update:
It seems that SwiperController was not instantiated and initialised. You can do it by overriding the initState method:
#override
void initState() {
controller = SwiperController();
controller.length = 10
//controller.fillRange(0, 10, SwiperController());
super.initState();
}
Related
I have a listview that shows some items, inside a StatefulWidget :
ListView.separated(
shrinkWrap: true,
itemBuilder: (context, index) {
return RowItem(
item: rowsList[index],
index: index,
);
},
separatorBuilder: (context, index) {
return Divider(
height: 20,
color: Colors.transparent,
);
},
itemCount: rowsList.length,
),
RowItem is a StatefulWidget too.
Everithing works fine when i add and remove items from rowsList, but i'm facing problems when i try to update an existing RowItem. This is my function for update:
void updateRow(int rowIndex, MyItem item) {
setState(() {
rowsList[rowIndex] = item;
});
}
but i still see inside listview the old values for updated item. (MyItem is an object that extends Equatable).
What's wrong?
try RowItem widget try this
var item;
#override
void initState() {
item = widget.item;
super.initState();
}
#override
void didUpdateWidget(covariant SleepDeckStepper oldWidget) {
item = widget.item;
super.didUpdateWidget(oldWidget);
}
problem is item parameter is not updating for RowItem
Reposting my comment. You should use a Key on each RowItem.
More on them from Emily Fortuna here.
I have a Instagram like app with stories on the top and then feed data. I want my feed list view to scroll to the top in a function (i.e. button click or whatever).
ScrollController _feedController;
#override
void initState() {
_feedController = new ScrollController();
_feedController.addListener(() {
print("scrolling");
});
_fetchData();
super.initState();
}
// This is in the build function.
return ListView.builder(
padding: EdgeInsets.all(0.0),
shrinkWrap: true,
controller: _feedController,
physics: ClampingScrollPhysics(),
itemCount: _listFeed.length,
itemBuilder: (BuildContext context, int index) {
return ProductWidget(
product: _listFeed[index],
navigateOnImage: true,
);
},
);
// This function should scroll the list view to the top.
refresh() {
_fetchData();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_feedController.animateTo(
0.0,
duration: Duration(milliseconds: 300),
curve: Curves.easeOut,
);
});
print("home screen refreshed");
}
I am initializing my controller on initState() and added a listener. neither the listener nor the controller's animateTo() function is working. I have also tried using WidgetsBinding.instance.addPostFrameCallback(). What am I missing.. ??
You need to call your fetchData function inside the addListener of ScrollController. Here is a proper example of the use of ScrollController:
#override
void initState() {
_feedController = new ScrollController()..addListener(function);
super.initState();
}
void function(){
print("scrolling");
_fetchData();
}
So basically I've been trying for a couple of days to allow users to close a modal bottom sheet when they get to the top of the ListView, when swiping on the ListView. However, when they swipe on the list view the widgets register as if I'm just trying to scroll up on the ListView. Is there a physics type for the ListView to close a modal bottom sheet when at the top or a different way to set up an ignore pointer for this?
This is what I've come up with and I hope I explained myself well enough that this problem is understood.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class ModalSheet extends StatefulWidget {
#override
_ModalSheetState createState() => _ModalSheetState();
}
ScrollController _scrollController = ScrollController();
bool close = false;
class _ModalSheetState extends State<ModalSheet> {
#override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.pixels < 1) {
if (_scrollController.position.userScrollDirection ==
ScrollDirection.forward) {
setState(() {
close = true;
});
} else {
setState(() {
close = false;
});
}
} else {
setState(() {
close = false;
});
}
print(_scrollController.position.pixels);
print(_scrollController.position.userScrollDirection);
print(close);
// print(close);
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Flexible(
child: IgnorePointer(
ignoring: close,
child: ListView.builder(
controller: _scrollController,
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) {
return ListTile(
title: Text('tile: ${index + 1}'),
);
},
),
),
),
],
),
);
}
}
EDIT: Thanks to #LearningJS888 for the package suggestion below to use this package! much appreciated
Can you elaborate what exactly you're trying to do?
A normal way of closing ModalBottomSheet is by Navigator.pop(context).
I have a flutter widget that attempts to solve soduku grids. I have class called SodukuSolver which does all the calculations and provides a List<String> of the current results. I call setState to refresh the list, but it does not update the screen.
Below, I'll try to include as much of the relevant code as I can. Full source is at https://github.com/mankowitz/soduku
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(title: "Soduku solver", home: Soduku());
}
}
class SodukuState extends State<Soduku> {
SodukuSolver ss;
List<String> _list;
int _changes = 0;
int _remaining = 81;
#override
Widget build(BuildContext context) {
final String _starting =
"750943002024005090300020000140089005093050170500360024000070009070400810400198057";
ss = new SodukuSolver(_starting);
_list = ss.getList();
return Scaffold(
appBar: AppBar(title: Text('Soduku solver'), actions: <Widget>[
// action button
IconButton(
icon: Icon(Icons.directions_walk),
onPressed: () {
_iterate();
},
),
]),
body: _buildGrid(),
);
}
Widget _buildGrid() {
return Column(children: <Widget>[
AspectRatio(
aspectRatio: 1.0,
child: Container(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 9,
),
itemBuilder: _buildGridItems,
itemCount: 81,
),
),
),
]);
}
Widget _buildGridItems(BuildContext context, int index) {
return GestureDetector(
child: GridTile(
child: Container(
child: Center(
child: Text(_list[index]),
),
),
),
);
}
void _iterate() {
setState(() {
_changes = ss.iterateSoduku();
_remaining = ss.empties();
_list = ss.getList();
});
}
}
class Soduku extends StatefulWidget {
#override
SodukuState createState() => SodukuState();
}
So the problem is that _iterate() is being called, and I can use the debugger to see that the internal state of SodukuSolver is being updated and it is even passing _list correctly, but the grid on screen doesn't update, even though _changes and _remaining do update.
You are creating new SodukuSolver with same _starting every time the widget builds and then obtaining _list from it. So you are overriding changes from previous iteration.
Looks like SodukuSolver creation should be performed once. You can override initState in SodukuState and initialise SodukuSolver there or initialise it in the same place where it is declared
Just add your code in the initState() method as following
#override
void initState() {
super.initState();
final String _starting =
"750943002024005090300020000140089005093050170500360024000070009070400810400198057";
ss = new SodukuSolver(_starting);
_list = ss.getList();
}
In your case, your list is not getting updated as setState() method will call your SodukuSolver() and ss.getList(); methods every time. because, setSate() ultimately calls build method to render every time.
So adding it inside your initState method will solve your issue. As it is getting called only once when the screen/route initialises.
How do I get the current scroll offset inside a Flutter ListView, GridView, SliverList`, etc?
If you're inside the scroll view use Scrollable.of(context).position.pixels.
If you're outside, you probably want to hand a ScrollController in as the controller argument of the scroll view, then you can read controller.offset.
Alternatively, use scroll notifications with NotificationListener.
This was asked on Flutter Gitter, and answered:
https://gitter.im/flutter/flutter?at=591243f18a05641b1167be0e
For someone else, looking for code implementation, you can use ScrollController like this:
Using NotificationListener:
NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
print(scrollNotification.metrics.pixels); // <-- This is it.
return false;
},
child: ListView.builder(
itemCount: 200,
itemBuilder: (c, i) => Text('Item $i'),
),
)
Using ScrollController.offset
final ScrollController _controller = ScrollController();
#override
void initState() {
super.initState();
_controller.addListener(() {
print(_controller.offset); // <-- This is it.
});
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
controller: _controller,
itemCount: 200,
itemBuilder: (c, i) => Text('Item $i'),
),
);
}
Another approach is with NotificationListener
NotificationListener(
child: ListView(
controller: _scrollController,
children: ...
),
onNotification: (notification) {
if (notification is ScrollEndNotification) {
print(_scrollController.position.pixels);
}
return false;
},
)