can not load data again with Stream flutter - flutter

I'm using a stream data to load data from API when app start up.But it had a problem, when It load the SearchPage widget, snapshot has data but when I change to other screen and back to SearchPage widget, it lost all data.
class _SearchPageState extends State<SearchPage> with TickerProviderStateMixin {
final locationsStream = StreamController<List<Weather>>.broadcast();
late final AnimationController _controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
late final Animation<double> _animation = CurvedAnimation(
parent: _controller,
curve: Curves.elasticOut,
);
#override
void dispose() {
_controller.dispose();
super.dispose();
locationsStream.close();
}
#override
void initState() {
loadData();
// TODO: implement initState
super.initState();
}
void loadData() async {
WeatherRepo weatherRepo = WeatherRepo();
List<Weather> rss = await weatherRepo.loadMainLocations();
locationsStream.sink.add(rss);
}
Code when I call Stream data:
Container(
height: 300,
child: StreamBuilder<List<Weather>>(
stream: locationsStream.stream,
initialData: null,
builder: (context, snap) {
if (!snap.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
final data = snap.data;
return Container(
height: 300,
child: CarouselSlider(
items: <Widget>[
for (Weather w in data!) MainLocation(location: w),
],
options: CarouselOptions(
height: 300.0,
autoPlay: true,
autoPlayInterval: Duration(seconds: 3),
autoPlayAnimationDuration: Duration(milliseconds: 2000),
autoPlayCurve: Curves.fastOutSlowIn,
enlargeCenterPage: true,
scrollDirection: Axis.horizontal,
))
);}
When app start up
And when I go to other screen and comeback

Try this
final StreamController<List<Weather>> locationsStream =
StreamController<List<Weather>>.broadcast();
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await loadData();
});
}
void loadData() async {
WeatherRepo weatherRepo = WeatherRepo();
List<Weather> rss = await weatherRepo.loadMainLocations();
locationsStream.add(rss);
}

Related

How to add delay between each repeat of animation in flutter

I have a SlideTransition with a container in my application, and it repeats forever, but i would like a delay after each repeat. so it would be like this:
Here's my code
late final AnimationController _animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1)
)..repeat(reverse: true); // Here there should be the 500 millisecond delay
late final Animation<Offset> _animation = Tween<Offset>(
begin: Offset.zero,
end: Offset(0, 1),
).animate(_animationController);
. . .
return Scaffold(
body: Center(
child: SlideTransition(
position: _animation,
child: Container(
height: 100,
width: 100,
color: Colors.red,
),
),
),
);
Just change the duration you want => await Future.delayed(Duration(seconds: 3));
I test it with seconds: 3 to get better idea.
late final AnimationController _animationController =
AnimationController(vsync: this, duration: const Duration(seconds: 3))
..forward();
#override
void initState() {
super.initState();
_animationController.addListener(() async {
print(_animationController.status);
if (_animationController.isCompleted) {
await Future.delayed(Duration(seconds: 3));
_animationController.reverse();
} else if (_animationController.isDismissed) {
await Future.delayed(Duration(seconds: 3));
_animationController.forward();
}
});
}
delay after each repeat :
#override
void initState() {// <-- add initstate
super.initState();
_animationController.forward(from: 0.0);
}
late final AnimationController _animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1))
//..repeat(reverse: true); // <-- comment this line
..addStatusListener((AnimationStatus status) { // <-- add listener
if (status == AnimationStatus.completed) {
Future.delayed(
Duration(milliseconds: _animationController.value == 0 ? 500 : 0),
() {
_animationController
.animateTo(_animationController.value == 0 ? 1 : 0);
});
}
});

How to scroll flutter web app using arrow keys

I just build and deployed a flutter web app. The problem I encountered is that it doesn't scroll when I press arrow keys, also there is no scroll bar. (Only 2 figure gesture scrolling is possible)
I'm using SingleChildScrollView() with the column as its child.
Is there a way to implement them?
Or just one of them?
The code from Karan works, but when the app is in Debug Mode, instead of using the event.logicalKey.debugName == "Arrow Up", we could use event.logicalKey == LogicalKeyboardKey.arrowUp which works in both the debug and release mode.
class _MyKeyboardScrollingPageState extends State<MyKeyboardScrollingPage> {
final ScrollController _controller = ScrollController();
final FocusNode _focusNode = FocusNode();
void _handleKeyEvent(RawKeyEvent event) {
var offset = _controller.offset;
if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
setState(() {
if (kReleaseMode) {
_controller.animateTo(offset - 200, duration: Duration(milliseconds: 30), curve: Curves.ease);
} else {
_controller.animateTo(offset - 200, duration: Duration(milliseconds: 30), curve: Curves.ease);
}
});
}
else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
setState(() {
if (kReleaseMode) {
_controller.animateTo(offset + 200, duration: Duration(milliseconds: 30), curve: Curves.ease);
} else {
_controller.animateTo(offset + 200, duration: Duration(milliseconds: 30), curve: Curves.ease);
}
});
}
}
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: RawKeyboardListener(
autoFocus = true,
focusNode = _focusNode,
onKey: _handleKeyEvent,
child: SingleChildScrollView(
controller: _controller,
child: SomeAwesomeWidget(),
),
),
);
}
}
I found one solution ...
Hope this helps someone with the same issue...
Using RawKeyboardListener(), we can listen to any keyboard stroke.
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _controller = ScrollController();
final FocusNode _focusNode = FocusNode()
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
void _handleKeyEvent(RawKeyEvent event) {
var offset = _controller.offset; //Getting current position
if (event.logicalKey.debugName == "Arrow Down") {
setState(() {
if (kReleaseMode) {
//This block only runs when the application was compiled in release mode.
_controller.animateTo(offset + 50,
duration: Duration(milliseconds: 200), curve: Curves.ease);
} else {
// This will only print useful information in debug mode.
// print(_controller.position); to get information..
_controller.animateTo(offset + 50,
duration: Duration(milliseconds: 200), curve: Curves.ease);
}
});
} else if (event.logicalKey.debugName == "Arrow Up"){
setState(() {
if (kReleaseMode) {
_controller.animateTo(offset - 50,
duration: Duration(milliseconds: 200), curve: Curves.ease);
} else {
_controller.animateTo(offset - 50,
duration: Duration(milliseconds: 200), curve: Curves.ease);
}
});
#override
Widget build(BuildContext context) {
return Scaffold(
body: RawKeyboardListener(
autofocus: true,
focusNode: _focusNode,
onKey: _handleKeyEvent,
child: SingleChildScrollView(
controller: _controller,
child:...
}
}
You can wrap ScrollBar to SingleChildScrollView to show scroll bar, like this:
Scrollbar(
child: SingleChildScrollView(
child: Container(),
));
For the answers that are mentioned above to work, you need the following imports:
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
The Most simplest way to Scroll using mouse or Keyboard Arrow keys on Flutter Web is
ListView(
primary: true,
scrollDirection: Axis.vertical,
children:
No need to pass any ScrollController

Call function from Stateful Widget from another StatefulWidget

So basically I have a ProfilePage which is a StatelessWidget and inside of it's build method I display a form called MyForm which is a StatefulWidget and a widget called FancyFab which is another StatefulWidget.
Here's an example of how they are displayed on the parent widget:
#override
Widget build(BuildContext globalContext) {
return Scaffold(
appBar: AppBar(title: Text('Profile')),
floatingActionButton: FancyFab(),
body: Center(
child: FutureBuilder(
future: initData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MyForm(data: snapshot.data);
} else if (snapshot.hasError) {
print(snapshot.error);
return new Container(width: 0.0, height: 0.0);
} else {
return Center(child: CircularProgressIndicator());
}
},
)
)
);
}
My problem lies in that I have a saveData() function in MyFormState which grabs values from each TextFormField controller and saves it on the database. I need to call this function from within my FancyFab widget but I can't find a proper way to do so. Or even access those TextFormField controllers from within my FancyFab widget. Any help or guidance will be greatly appreciated.
EDIT
Here's how I implemented the FancyFab widget:
class FancyFab extends StatefulWidget {
final String tooltip;
final IconData icon;
String photo;
TextEditingController birthController;
TextEditingController firstController;
TextEditingController lastController;
TextEditingController emailController;
TextEditingController phoneController;
TextEditingController associationController;
TextEditingController countryController;
final Function saveData;
FancyFab({
this.tooltip,
this.icon,
this.saveData,
this.firstController,
this.lastController,
this.emailController,
this.phoneController,
this.associationController,
this.countryController,
this.birthController,
this.photo});
#override
_FancyFabState createState() => _FancyFabState();
}
class _FancyFabState extends State<FancyFab>
with SingleTickerProviderStateMixin {
bool isOpened = false;
AnimationController _animationController;
Animation<Color> _buttonColor;
Animation<double> _animateIcon;
Animation<double> _translateButton;
Curve _curve = Curves.easeOut;
double _fabHeight = 56.0;
#override
initState() {
_animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 500))
..addListener(() {
setState(() {});
});
_animateIcon =
Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
_buttonColor = ColorTween(
begin: Colors.pink,
end: Colors.red,
).animate(CurvedAnimation(
parent: _animationController,
curve: Interval(
0.00,
1.00,
curve: Curves.linear,
),
));
_translateButton = Tween<double>(
begin: _fabHeight,
end: -14.0,
).animate(CurvedAnimation(
parent: _animationController,
curve: Interval(
0.0,
0.75,
curve: _curve,
),
));
super.initState();
}
#override
dispose() {
_animationController.dispose();
super.dispose();
}
animate() {
if (!isOpened) {
_animationController.forward();
} else {
_animationController.reverse();
}
isOpened = !isOpened;
}
Widget save() {
return Container(
child: FloatingActionButton(
heroTag: 'saveBtn',
onPressed: () {
},
tooltip: 'Save',
child: Icon(Icons.save),
),
);
}
Widget image() {
return Container(
child: FloatingActionButton(
heroTag: 'imageBtn',
onPressed: () async {
File file = await FilePicker.getFile(type: FileType.IMAGE);
AlertDialog alert = AlertDialog(
title: Text('Uploading photo'),
titlePadding: EdgeInsets.all(20.0),
contentPadding: EdgeInsets.all(20.0),
elevation:10,
content: CircularProgressIndicator(),
);
final StorageReference storageRef = FirebaseStorage.instance.ref().child(file.path);
final String fileName = file.path;
final StorageUploadTask uploadTask = storageRef.putFile(
File(fileName),
);
final StorageTaskSnapshot downloadUrl =
(await uploadTask.onComplete);
final String url = (await downloadUrl.ref.getDownloadURL());
print('URL Is $url');
setState(() {
widget.photo = url;
});
},
tooltip: 'Image',
child: Icon(Icons.image),
),
);
}
Widget toggle() {
return Container(
child: FloatingActionButton(
backgroundColor: _buttonColor.value,
onPressed: animate,
heroTag: 'toggleBtn',
tooltip: 'Toggle',
child: AnimatedIcon(
icon: AnimatedIcons.menu_close,
progress: _animateIcon,
),
),
);
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Transform(
transform: Matrix4.translationValues(
0.0,
_translateButton.value * 2.0,
0.0,
),
child: save(),
),
Transform(
transform: Matrix4.translationValues(
0.0,
_translateButton.value * 1.0,
0.0,
),
child: image(),
),
toggle(),
],
);
}
}
As far as I can see, there is a slight issue with the data-flow of the application, for example, strictly from a fucntionality based observation, the data and the trigger (FancyFab) should be in the same widget or in an directly accessible widget. But nevertheless if you want to continue, here is a very primitive (VERY) way to do it.
I managed to solve this by nesting a Scaffold inside MyForm widget. Then the tree changed and my FancyFab widget was now a child from MyForm widget. Next I passed parent's saveData() function and all my controllers to my child widget and that way I was able to call parent function providing the appropiate data. The fix was a follows:
Solution
Parent widget (MyForm)
class MyFormState extends State<MyForm> {
User user;
TextEditingController birthController = TextEditingController();
TextEditingController firstController = TextEditingController();
TextEditingController lastController = TextEditingController();
TextEditingController emailController = TextEditingController();
TextEditingController phoneController = TextEditingController();
TextEditingController associationController = TextEditingController();
TextEditingController countryController = TextEditingController();
#override
void initState() {
super.initState();
user = widget.data[1];
firstController.text = user.firstName;
lastController.text = user.lastName;
countryController.text = user.country;
birthController.text = user.dateBirth;
emailController.text = user.email;
phoneController.text = user.phone;
associationController.text = user.association;
}
_updatePhoto(String text) {
setState(() {
user.photo = text;
});
}
_saveData(data, BuildContext ctx) async {
FirebaseUser fireUser= await FirebaseAuth.instance.currentUser();
var uid = fireUser.uid;
await Firestore.instance.collection('users').document(uid).updateData(data).then((val) {
AlertDialog alert = AlertDialog(
title: Text('Confirmation'),
titlePadding: EdgeInsets.all(20.0),
// contentPadding: EdgeInsets.all(20.0),
elevation:10,
content: Text('Your profile has been saved.')
);
showDialog(context: ctx,
builder: (BuildContext context){
return alert;
});
})
.catchError((err) {
final snackBar = SnackBar(
content: Text('There have been an error updating your profile' + err.toString()),
elevation: 10,
);
Scaffold.of(ctx).showSnackBar(snackBar);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FancyFab(
parentAction: _updatePhoto,
saveData: _saveData,
firstController: firstController,
lastController: lastController,
emailController: emailController,
countryController: countryController,
associationController: associationController,
phoneController: phoneController,
birthController: birthController,
photo: user.photo),
body:Form(
//more UI
)
);
}
}
Child widget (FancyFab)
class FancyFab extends StatefulWidget {
final void Function(String value) parentAction;
final void Function(dynamic data, BuildContext ctx) saveData;
final String tooltip;
final IconData icon;
String photo;
TextEditingController birthController;
TextEditingController firstController;
TextEditingController lastController;
TextEditingController emailController;
TextEditingController phoneController;
TextEditingController associationController;
TextEditingController countryController;
FancyFab({
this.parentAction,
this.tooltip,
this.icon,
this.saveData,
this.firstController,
this.lastController,
this.emailController,
this.phoneController,
this.associationController,
this.countryController,
this.birthController,
this.photo});
#override
_FancyFabState createState() => _FancyFabState();
}
Then I could just call parent function using widget.parentFunction(data) on my child widget state.
Special thanks to #diegoveloper for providing with a great article explaining the types of widgets interactions.

How to automatically scroll a PageView with some delay that is made without using a builder?

I've made a PageView that acts as an image carousel.
How do I let it scroll automatically between its pages infinitely after some delay in Flutter?
new PageView(
children: List<Widget> {
new Container(
decoration: BoxDecoration(
image: DecorationImage(image: new AssetImage(images[0]),
fit: BoxFit.cover
)
)
),
new Container(
decoration: BoxDecoration(
image: DecorationImage(image: new AssetImage(images[1]),
fit: BoxFit.cover
)
)
),
new Container(
decoration: BoxDecoration(
image: DecorationImage(image: new AssetImage(images[2]),
fit: BoxFit.cover
)
)
)
}
)
You need to add a PageController to your PageView. Then on initState() you can start a Timer.periodic() where you just jump from page to page. Like this:
Note: You have to cancel the timer when dispose the page or other events.
int _currentPage = 0;
Timer _timer;
PageController _pageController = PageController(
initialPage: 0,
);
#override
void initState() {
super.initState();
_timer = Timer.periodic(Duration(seconds: 5), (Timer timer) {
if (_currentPage < 2) {
_currentPage++;
} else {
_currentPage = 0;
}
_pageController.animateToPage(
_currentPage,
duration: Duration(milliseconds: 350),
curve: Curves.easeIn,
);
});
}
#override
void dispose() {
super.dispose();
_timer?.cancel();
}
#override
Widget build(BuildContext context) {
return PageView(
controller: _pageController,
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: new AssetImage(images[0]),
fit: BoxFit.cover,
),
),
),
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: new AssetImage(images[1]),
fit: BoxFit.cover,
),
),
),
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: new AssetImage(images[2]),
fit: BoxFit.cover,
),
),
),
],
);
}
By the way you need to import 'dart:async' for using Timer.
the #GaboBrandX's answer is the correct one, so I added some code to reverse the animation, for example, it will animate from 0,1,2 pages and when reaching the end, it will reverse to 2,1,0.
final PageController _pageController = PageController(initialPage: 0);
int _currentPage = 0;
bool end = false;
#override
void initState() {
super.initState();
Timer.periodic(Duration(seconds: 2), (Timer timer) {
if (_currentPage == 2) {
end = true;
} else if (_currentPage == 0) {
end = false;
}
if (end == false) {
_currentPage++;
} else {
_currentPage--;
}
_pageController.animateToPage(
_currentPage,
duration: Duration(milliseconds: 1000),
curve: Curves.easeIn,
);
});}
The most effective way for me was to implement animation controllers. AnimationController and Animation. Inside a StatefulWidget with a page controller in the page view.
import 'package:flutter/material.dart';
class ChangePageViewAuto extends StatefulWidget {
#override
_ChangePageViewAutoState createState() => _ChangePageViewAutoState();
}
class _ChangePageViewAutoState extends State<ChangePageViewAuto>
with SingleTickerProviderStateMixin {
//declare the variables
AnimationController _animationController;
Animation<double> _nextPage;
int _currentPage = 0;
PageController _pageController = PageController(initialPage: 0);
#override
void initState() {
super.initState();
//Start at the controller and set the time to switch pages
_animationController =
new AnimationController(vsync: this, duration: Duration(seconds: 10));
_nextPage = Tween(begin: 0.0, end: 1.0).animate(_animationController);
//Add listener to AnimationController for know when end the count and change to the next page
_animationController.addListener(() {
if (_animationController.status == AnimationStatus.completed) {
_animationController.reset(); //Reset the controller
final int page = 4; //Number of pages in your PageView
if (_currentPage < page) {
_currentPage++;
_pageController.animateToPage(_currentPage,
duration: Duration(milliseconds: 300), curve: Curves.easeInSine);
} else {
_currentPage = 0;
}
}
});
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
_animationController.forward(); //Start controller with widget
print(_nextPage.value);
return PageView.builder(
itemCount: 4,
scrollDirection: Axis.horizontal,
controller: _pageController,
onPageChanged: (value) {
//When page change, start the controller
_animationController.forward();
},
itemBuilder: (BuildContext context, int index) {
return Container();
});
}
}

How to create a listview that makes centering the desired element

I'm doing something similar to this video: https://youtu.be/fpqHUp4Sag0
With the following code I generate the listview but when using the controller in this way the element is located at the top of the listview and I need it to be centered
Widget _buildLyric() {
return ListView.builder(
itemBuilder: (BuildContext context, int index) => _buildPhrase(lyric[index]),
itemCount: lyric.length,
itemExtent: 90.0,
controller: _scrollController,
);
}
void goToNext() {
i += 1;
if (i == lyric.length - 1) {
setState(() {
finishedSync = true;
});
}
syncLyric.addPhrase(
lyric[i], playerController.value.position.inMilliseconds);
_scrollController.animateTo(i*90.0,
curve: Curves.ease, duration: new Duration(milliseconds: 300));
}
Using center and shrinkWrap: true
Center(
child: new ListView.builder(
shrinkWrap: true,
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return Text("Centered item");
},
),
);
You're going to have to do some math! (Nooooo, not the mathssssss).
It seems as though your goToNext() function is called while the app is running, rather than during build time. This makes it a little easier - you can simply use context.size. Otherwise you'd have to use a LayoutBuilder and maxHeight.
You can then divide this in two to get the half, then add/subtract whatever you need to get your item positioned how you want (since you've specified it's height as 90 in the example, I assume you could use 45 to get what you want).
Here's an example you can paste into a file to run:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(Wid());
class Wid extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Scrolling by time"),
),
body: new Column(
children: <Widget>[
Expanded(child: Container()),
Container(
height: 300.0,
color: Colors.orange,
child: ScrollsByTime(
itemExtent: 90.0,
),
),
Expanded(child: Container()),
],
),
),
);
}
}
class ScrollsByTime extends StatefulWidget {
final double itemExtent;
const ScrollsByTime({Key key, #required this.itemExtent}) : super(key: key);
#override
ScrollsByTimeState createState() {
return new ScrollsByTimeState();
}
}
class ScrollsByTimeState extends State<ScrollsByTime> {
final ScrollController _scrollController = new ScrollController();
#override
void initState() {
super.initState();
Timer.periodic(Duration(seconds: 1), (timer) {
_scrollController.animateTo(
(widget.itemExtent * timer.tick) - context.size.height / 2.0 + widget.itemExtent / 2.0,
duration: Duration(milliseconds: 300),
curve: Curves.ease,
);
});
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, index) {
return Center(child: Text("Item $index"));
},
itemExtent: widget.itemExtent,
controller: _scrollController,
);
}
}
I had a similar problem, but with the horizontal listview. You should use ScrollController and NotificationListener. When you receive endScroll event you should calculate offset and use scroll controller animateTo method to center your items.
class SwipeCalendarState extends State<SwipeCalendar> {
List<DateTime> dates = List();
ScrollController _controller;
final itemWidth = 100.0;
#override
void initState() {
_controller = ScrollController();
_controller.addListener(_scrollListener);
for (var i = 1; i < 365; i++) {
var date = DateTime.now().add(Duration(days: i));
dates.add(date);
}
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
height: 200,
child: Stack(
children: <Widget>[buildListView()],
),
);
}
void _onStartScroll(ScrollMetrics metrics) {
}
void _onUpdateScroll(ScrollMetrics metrics){
}
void _onEndScroll(ScrollMetrics metrics){
print("scroll before = ${metrics.extentBefore}");
print("scroll after = ${metrics.extentAfter}");
print("scroll inside = ${metrics.extentInside}");
var halfOfTheWidth = itemWidth/2;
var offsetOfItem = metrics.extentBefore%itemWidth;
if (offsetOfItem < halfOfTheWidth) {
final offset = metrics.extentBefore - offsetOfItem;
print("offsetOfItem = ${offsetOfItem} offset = ${offset}");
Future.delayed(Duration(milliseconds: 50), (){
_controller.animateTo(offset, duration: Duration(milliseconds: 100), curve: Curves.linear);
});
} else if (offsetOfItem > halfOfTheWidth){
final offset = metrics.extentBefore + offsetOfItem;
print("offsetOfItem = ${offsetOfItem} offset = ${offset}");
Future.delayed(Duration(milliseconds: 50), (){
_controller.animateTo(offset, duration: Duration(milliseconds: 100), curve: Curves.linear);
});
}
}
Widget buildListView() {
return NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollStartNotification) {
_onStartScroll(scrollNotification.metrics);
} else if (scrollNotification is ScrollUpdateNotification) {
_onUpdateScroll(scrollNotification.metrics);
} else if (scrollNotification is ScrollEndNotification) {
_onEndScroll(scrollNotification.metrics);
}
},
child: ListView.builder(
itemCount: dates.length,
controller: _controller,
scrollDirection: Axis.horizontal,
itemBuilder: (context, i) {
var item = dates[i];
return Container(
height: 100,
width: itemWidth,
child: Center(
child: Text("${item.day}.${item.month}.${item.year}"),
),
);
}),
);
}
}
IMO the link you have posted had some wheel like animation. Flutter provides this type of animation with ListWheelScrollView and rest can be done with the fade in animation and change in font weight with ScrollController.