Reputation: 1125
like the title I'm trying to change with animation the Scaffold background-color
. On onPageChanged PageView
I trigger the animation. So far so good. The problem is with more colors. I mean, I have to take the colors from an API and when the user scrolls the card (PageView
) I have to fit the color of that card.
Any suggestions?
This is the current code (with preview) for 2 colors: DartPad.
Thanks in advance :)
Upvotes: 0
Views: 2983
Reputation: 6980
full example
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'stackoverflow question',
home: SafeArea(
top: false,
bottom: true,
child: HomepageScreen(),
),
);
}
}
class HomepageScreen extends StatefulWidget {
const HomepageScreen({Key? key}) : super(key: key);
@override
_HomepageScreenState createState() => _HomepageScreenState();
}
class _HomepageScreenState extends State<HomepageScreen>
with SingleTickerProviderStateMixin {
AnimationController? _controller;
Animation<Color>? animation;
final colors = <TweenSequenceItem<Color>>[
TweenSequenceItem(
weight: 1.0,
tween: Tween<Color>(begin: Colors.red, end: Colors.blue),
),
TweenSequenceItem(
weight: 1.0,
tween: Tween<Color>(begin: Colors.blue, end: Colors.green),
),
TweenSequenceItem(
weight: 1.0,
tween: Tween<Color>(begin: Colors.green, end: Colors.yellow),
),
TweenSequenceItem(
weight: 1.0,
tween: Tween<Color>(begin: Colors.yellow, end: Colors.red),
),
];
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 600),
vsync: this,
);
animation = TweenSequence<Color>(colors).animate(_controller!)..addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: animation!.value,
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: PageView.builder(
physics: new PageScrollPhysics(),
itemCount: colors.length,
controller: PageController(viewportFraction: 0.8),
onPageChanged: ((int index) {
_controller!.animateTo(index / colors.length);
}),
itemBuilder: (_, i) {
return Padding(
padding:
EdgeInsets.only(left: i % 2 == 0 ? 0 : 15, bottom: 20),
child: Container(),
);
},
),
),
],
),
),
);
}
}
Upvotes: 1
Reputation: 1263
Use a TweenSequence<Color>
Assuming the weight of each color in the sequence is the same, you can find a given color with index / colors.length
as I show in the onPageChanged
callback.
Given this, _controller.animateTo(index / colors.length)
will take the duration specified in the AnimationController
to animation in either direction to from the current color to the new color.
Here's a live demo
Here's the relevant code (only showing what was changed from yours). I changed the duration and animation physics for personal preference. By all means, use what you prefer.
class _HomepageScreenState extends State<HomepageScreen>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<Color> animation;
final colors = <TweenSequenceItem<Color>>[
TweenSequenceItem(
weight: 1.0,
tween: ColorTween(begin: Colors.red, end: Colors.blue),
),
TweenSequenceItem(
weight: 1.0,
tween: ColorTween(begin: Colors.blue, end: Colors.green),
),
TweenSequenceItem(
weight: 1.0,
tween: ColorTween(begin: Colors.green, end: Colors.yellow),
),
TweenSequenceItem(
weight: 1.0,
tween: ColorTween(begin: Colors.yellow, end: Colors.red),
),
];
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 600),
vsync: this,
);
animation = TweenSequence<Color>(colors).animate(_controller)..addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: animation.value,
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: PageView.builder(
physics: new PageScrollPhysics(),
itemCount: colors.length,
controller: PageController(viewportFraction: 0.8),
onPageChanged: ((int index) {
_controller.animateTo(index / colors.length);
}),
itemBuilder: (_, i) {
return Padding(
padding:
EdgeInsets.only(left: i % 2 == 0 ? 0 : 15, bottom: 20),
child: Container(),
);
},
),
),
],
),
),
);
}
}
Upvotes: 4