Animating widget positions as the screen scrolls in flutter (GIF included)Flutter Layout: How can I put a Row inside a Flex (or another Row) in Flutter? Also using Stack widgetflutter : gif animation listener in ImageAbsolute position of Flutter widgetsAnimate ListView item to full screen in FlutterAnimating widgets positions while scrollingFlutter : Bad state: Stream has already been listened toPositioned Widget Animation with FlutterFlutter - Include Widget on Conditionanimate show or hide widgets with flutterHow to animate expandable Flutter widget to slide it out of the screen
Is it possible to put a rectangle as background in the author section?
Aragorn's "guise" in the Orthanc Stone
Did arcade monitors have same pixel aspect ratio as TV sets?
WiFi Thermostat, No C Terminal on Furnace
Pre-mixing cryogenic fuels and using only one fuel tank
Drawing ramified coverings with tikz
How do you make your own symbol when Detexify fails?
When were female captains banned from Starfleet?
What is this cable/device?
Which one is correct as adjective “protruding” or “protruded”?
Yosemite Fire Rings - What to Expect?
How to bake one texture for one mesh with multiple textures blender 2.8
How could a planet have erratic days?
What was this official D&D 3.5e Lovecraft-flavored rulebook?
Travelling outside the UK without a passport
Is there a name for this algorithm to calculate the concentration of a mixture of two solutions containing the same solute?
Longest common substring in linear time
Electoral considerations aside, what are potential benefits, for the US, of policy changes proposed by the tweet recognizing Golan annexation?
A social experiment. What is the worst that can happen?
On a tidally locked planet, would time be quantized?
Why electric field inside a cavity of a non-conducting sphere not zero?
What does routing an IP address mean?
Does a 'pending' US visa application constitute a denial?
Can I sign legal documents with a smiley face?
Animating widget positions as the screen scrolls in flutter (GIF included)
Flutter Layout: How can I put a Row inside a Flex (or another Row) in Flutter? Also using Stack widgetflutter : gif animation listener in ImageAbsolute position of Flutter widgetsAnimate ListView item to full screen in FlutterAnimating widgets positions while scrollingFlutter : Bad state: Stream has already been listened toPositioned Widget Animation with FlutterFlutter - Include Widget on Conditionanimate show or hide widgets with flutterHow to animate expandable Flutter widget to slide it out of the screen
I am trying to animate two Rows of widgets to collapse into 1 Row of these widgets as one scrolls. I am trying to achieve this behavior inside a SliverAppBar
.
For clarification I have included a GIF here for reference. I would like the behavior you see in the app bar, but instead of 1 row to 2, i would like 2 row becoming 1.
https://media.giphy.com/media/2A4CP65QjamZC3K4c8/giphy.gif
Here is a quick snippet of what I have so far. I wrapped 2 Row
widgets that contain 3 shrinkableBox
widgets each into a Wrap
widget. I dynamically adjust the size of these boxes by hooking into _scrollController.offset
and doing some calculations. The rows do move around dynamically but they dont animate and move abruptly instead.
double kExpandedHeight = 300.0;
Widget build(BuildContext context) {
double size = !_scrollController.hasClients || _scrollController.offset == 0 ? 75.0 : 75 - math.min(45.0, (45 / kExpandedHeight * math.min(_scrollController.offset, kExpandedHeight) * 1.5));
return Scaffold(
body: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: kExpandedHeight,
title: new Text(
"Title!",
),
bottom: PreferredSize(child: Wrap(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
],
),
],
), preferredSize: new Size.fromHeight(55),),
)...
...Other sliver list content here...
...
user-interface animation flutter
add a comment |
I am trying to animate two Rows of widgets to collapse into 1 Row of these widgets as one scrolls. I am trying to achieve this behavior inside a SliverAppBar
.
For clarification I have included a GIF here for reference. I would like the behavior you see in the app bar, but instead of 1 row to 2, i would like 2 row becoming 1.
https://media.giphy.com/media/2A4CP65QjamZC3K4c8/giphy.gif
Here is a quick snippet of what I have so far. I wrapped 2 Row
widgets that contain 3 shrinkableBox
widgets each into a Wrap
widget. I dynamically adjust the size of these boxes by hooking into _scrollController.offset
and doing some calculations. The rows do move around dynamically but they dont animate and move abruptly instead.
double kExpandedHeight = 300.0;
Widget build(BuildContext context) {
double size = !_scrollController.hasClients || _scrollController.offset == 0 ? 75.0 : 75 - math.min(45.0, (45 / kExpandedHeight * math.min(_scrollController.offset, kExpandedHeight) * 1.5));
return Scaffold(
body: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: kExpandedHeight,
title: new Text(
"Title!",
),
bottom: PreferredSize(child: Wrap(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
],
),
],
), preferredSize: new Size.fromHeight(55),),
)...
...Other sliver list content here...
...
user-interface animation flutter
add a comment |
I am trying to animate two Rows of widgets to collapse into 1 Row of these widgets as one scrolls. I am trying to achieve this behavior inside a SliverAppBar
.
For clarification I have included a GIF here for reference. I would like the behavior you see in the app bar, but instead of 1 row to 2, i would like 2 row becoming 1.
https://media.giphy.com/media/2A4CP65QjamZC3K4c8/giphy.gif
Here is a quick snippet of what I have so far. I wrapped 2 Row
widgets that contain 3 shrinkableBox
widgets each into a Wrap
widget. I dynamically adjust the size of these boxes by hooking into _scrollController.offset
and doing some calculations. The rows do move around dynamically but they dont animate and move abruptly instead.
double kExpandedHeight = 300.0;
Widget build(BuildContext context) {
double size = !_scrollController.hasClients || _scrollController.offset == 0 ? 75.0 : 75 - math.min(45.0, (45 / kExpandedHeight * math.min(_scrollController.offset, kExpandedHeight) * 1.5));
return Scaffold(
body: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: kExpandedHeight,
title: new Text(
"Title!",
),
bottom: PreferredSize(child: Wrap(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
],
),
],
), preferredSize: new Size.fromHeight(55),),
)...
...Other sliver list content here...
...
user-interface animation flutter
I am trying to animate two Rows of widgets to collapse into 1 Row of these widgets as one scrolls. I am trying to achieve this behavior inside a SliverAppBar
.
For clarification I have included a GIF here for reference. I would like the behavior you see in the app bar, but instead of 1 row to 2, i would like 2 row becoming 1.
https://media.giphy.com/media/2A4CP65QjamZC3K4c8/giphy.gif
Here is a quick snippet of what I have so far. I wrapped 2 Row
widgets that contain 3 shrinkableBox
widgets each into a Wrap
widget. I dynamically adjust the size of these boxes by hooking into _scrollController.offset
and doing some calculations. The rows do move around dynamically but they dont animate and move abruptly instead.
double kExpandedHeight = 300.0;
Widget build(BuildContext context) {
double size = !_scrollController.hasClients || _scrollController.offset == 0 ? 75.0 : 75 - math.min(45.0, (45 / kExpandedHeight * math.min(_scrollController.offset, kExpandedHeight) * 1.5));
return Scaffold(
body: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: kExpandedHeight,
title: new Text(
"Title!",
),
bottom: PreferredSize(child: Wrap(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
ShrinkableBox(
onClick: ()
print("tapped");
,
size: size,
),
],
),
],
), preferredSize: new Size.fromHeight(55),),
)...
...Other sliver list content here...
...
user-interface animation flutter
user-interface animation flutter
asked Mar 8 at 4:26
smblsmbl
587
587
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
You could use a Stack together with Positioned widgets to position the ShrinkableBoxes as you need. Since what controls the animation is the scroll offset, you don't need to use animated widgets or an animation controller or something like it. Here's a working example which calculates the positions by linearly interpolating the initial and final position of the boxes (you can get different animation paths by changing the Curves.linear to other curves):
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
void main()
runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget
@override
State createState() => HomeState();
class HomeState extends State<Home>
static const double kExpandedHeight = 300.0;
static const double kInitialSize = 75.0;
static const double kFinalSize = 30.0;
static const List<Color> kBoxColors = [
Colors.red,
Colors.green,
Colors.yellow,
Colors.purple,
Colors.orange,
Colors.grey,
];
ScrollController _scrollController = new ScrollController();
@override
void initState()
_scrollController.addListener(()
setState(() /* State being set is the Scroll Controller's offset */ );
);
@override
void dispose()
_scrollController.dispose();
Widget build(BuildContext context)
Widget buildAppBarBottom(double size)
double t = (size - kInitialSize) / (kFinalSize - kInitialSize);
const double initialContainerHeight = 2 * kInitialSize;
const double finalContainerHeight = kFinalSize;
return Container(
height: lerpDouble(initialContainerHeight, finalContainerHeight, t),
child: LayoutBuilder(
builder: (context, constraints)
List<Widget> stackChildren = [];
for (int i = 0; i < 6; i++)
Offset offset = getInterpolatedOffset(i, constraints, t);
stackChildren.add(Positioned(
left: offset.dx,
top: offset.dy,
child: buildSizedBox(size, kBoxColors[i]),
));
return Stack(children: stackChildren);
,
),
);
Offset getInterpolatedOffset(int index, BoxConstraints constraints, double t)
Curve curve = Curves.linear;
double curveT = curve.transform(t);
Offset a = getOffset(index, constraints, kInitialSize, 3);
Offset b = getOffset(index, constraints, kFinalSize, 6);
return Offset(
lerpDouble(a.dx, b.dx, curveT),
lerpDouble(a.dy, b.dy, curveT),
);
Offset getOffset(int index, BoxConstraints constraints, double size, int columns)
int x = index % columns;
int y = index ~/ columns;
double horizontalMargin = (constraints.maxWidth - size * columns) / 2;
return Offset(horizontalMargin + x * size, y * size);
Widget buildSizedBox(double size, Color color)
return Container(
height: size,
width: size,
color: color,
);
New contributor
This is exactly what i wanted! How were you able to figure this out? This is a pretty complex piece of code. I would like to learn animations like this for myself as well.
– smbl
Mar 19 at 3:26
@smbl Thanks! I guess I've had a fair share of struggles with animations in Flutter hehe. Have you checked out the Animations section of the Flutter website? While it explains how to do more complex animations, you might also want to check out the implicitly animated widgets, which are still powerful and simpler to use, such as AnimatedContainer: flutter.dev/docs/development/ui/widgets/animation
– Luis Fernando Trivelatto
Mar 19 at 20:33
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55056721%2fanimating-widget-positions-as-the-screen-scrolls-in-flutter-gif-included%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You could use a Stack together with Positioned widgets to position the ShrinkableBoxes as you need. Since what controls the animation is the scroll offset, you don't need to use animated widgets or an animation controller or something like it. Here's a working example which calculates the positions by linearly interpolating the initial and final position of the boxes (you can get different animation paths by changing the Curves.linear to other curves):
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
void main()
runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget
@override
State createState() => HomeState();
class HomeState extends State<Home>
static const double kExpandedHeight = 300.0;
static const double kInitialSize = 75.0;
static const double kFinalSize = 30.0;
static const List<Color> kBoxColors = [
Colors.red,
Colors.green,
Colors.yellow,
Colors.purple,
Colors.orange,
Colors.grey,
];
ScrollController _scrollController = new ScrollController();
@override
void initState()
_scrollController.addListener(()
setState(() /* State being set is the Scroll Controller's offset */ );
);
@override
void dispose()
_scrollController.dispose();
Widget build(BuildContext context)
Widget buildAppBarBottom(double size)
double t = (size - kInitialSize) / (kFinalSize - kInitialSize);
const double initialContainerHeight = 2 * kInitialSize;
const double finalContainerHeight = kFinalSize;
return Container(
height: lerpDouble(initialContainerHeight, finalContainerHeight, t),
child: LayoutBuilder(
builder: (context, constraints)
List<Widget> stackChildren = [];
for (int i = 0; i < 6; i++)
Offset offset = getInterpolatedOffset(i, constraints, t);
stackChildren.add(Positioned(
left: offset.dx,
top: offset.dy,
child: buildSizedBox(size, kBoxColors[i]),
));
return Stack(children: stackChildren);
,
),
);
Offset getInterpolatedOffset(int index, BoxConstraints constraints, double t)
Curve curve = Curves.linear;
double curveT = curve.transform(t);
Offset a = getOffset(index, constraints, kInitialSize, 3);
Offset b = getOffset(index, constraints, kFinalSize, 6);
return Offset(
lerpDouble(a.dx, b.dx, curveT),
lerpDouble(a.dy, b.dy, curveT),
);
Offset getOffset(int index, BoxConstraints constraints, double size, int columns)
int x = index % columns;
int y = index ~/ columns;
double horizontalMargin = (constraints.maxWidth - size * columns) / 2;
return Offset(horizontalMargin + x * size, y * size);
Widget buildSizedBox(double size, Color color)
return Container(
height: size,
width: size,
color: color,
);
New contributor
This is exactly what i wanted! How were you able to figure this out? This is a pretty complex piece of code. I would like to learn animations like this for myself as well.
– smbl
Mar 19 at 3:26
@smbl Thanks! I guess I've had a fair share of struggles with animations in Flutter hehe. Have you checked out the Animations section of the Flutter website? While it explains how to do more complex animations, you might also want to check out the implicitly animated widgets, which are still powerful and simpler to use, such as AnimatedContainer: flutter.dev/docs/development/ui/widgets/animation
– Luis Fernando Trivelatto
Mar 19 at 20:33
add a comment |
You could use a Stack together with Positioned widgets to position the ShrinkableBoxes as you need. Since what controls the animation is the scroll offset, you don't need to use animated widgets or an animation controller or something like it. Here's a working example which calculates the positions by linearly interpolating the initial and final position of the boxes (you can get different animation paths by changing the Curves.linear to other curves):
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
void main()
runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget
@override
State createState() => HomeState();
class HomeState extends State<Home>
static const double kExpandedHeight = 300.0;
static const double kInitialSize = 75.0;
static const double kFinalSize = 30.0;
static const List<Color> kBoxColors = [
Colors.red,
Colors.green,
Colors.yellow,
Colors.purple,
Colors.orange,
Colors.grey,
];
ScrollController _scrollController = new ScrollController();
@override
void initState()
_scrollController.addListener(()
setState(() /* State being set is the Scroll Controller's offset */ );
);
@override
void dispose()
_scrollController.dispose();
Widget build(BuildContext context)
Widget buildAppBarBottom(double size)
double t = (size - kInitialSize) / (kFinalSize - kInitialSize);
const double initialContainerHeight = 2 * kInitialSize;
const double finalContainerHeight = kFinalSize;
return Container(
height: lerpDouble(initialContainerHeight, finalContainerHeight, t),
child: LayoutBuilder(
builder: (context, constraints)
List<Widget> stackChildren = [];
for (int i = 0; i < 6; i++)
Offset offset = getInterpolatedOffset(i, constraints, t);
stackChildren.add(Positioned(
left: offset.dx,
top: offset.dy,
child: buildSizedBox(size, kBoxColors[i]),
));
return Stack(children: stackChildren);
,
),
);
Offset getInterpolatedOffset(int index, BoxConstraints constraints, double t)
Curve curve = Curves.linear;
double curveT = curve.transform(t);
Offset a = getOffset(index, constraints, kInitialSize, 3);
Offset b = getOffset(index, constraints, kFinalSize, 6);
return Offset(
lerpDouble(a.dx, b.dx, curveT),
lerpDouble(a.dy, b.dy, curveT),
);
Offset getOffset(int index, BoxConstraints constraints, double size, int columns)
int x = index % columns;
int y = index ~/ columns;
double horizontalMargin = (constraints.maxWidth - size * columns) / 2;
return Offset(horizontalMargin + x * size, y * size);
Widget buildSizedBox(double size, Color color)
return Container(
height: size,
width: size,
color: color,
);
New contributor
This is exactly what i wanted! How were you able to figure this out? This is a pretty complex piece of code. I would like to learn animations like this for myself as well.
– smbl
Mar 19 at 3:26
@smbl Thanks! I guess I've had a fair share of struggles with animations in Flutter hehe. Have you checked out the Animations section of the Flutter website? While it explains how to do more complex animations, you might also want to check out the implicitly animated widgets, which are still powerful and simpler to use, such as AnimatedContainer: flutter.dev/docs/development/ui/widgets/animation
– Luis Fernando Trivelatto
Mar 19 at 20:33
add a comment |
You could use a Stack together with Positioned widgets to position the ShrinkableBoxes as you need. Since what controls the animation is the scroll offset, you don't need to use animated widgets or an animation controller or something like it. Here's a working example which calculates the positions by linearly interpolating the initial and final position of the boxes (you can get different animation paths by changing the Curves.linear to other curves):
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
void main()
runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget
@override
State createState() => HomeState();
class HomeState extends State<Home>
static const double kExpandedHeight = 300.0;
static const double kInitialSize = 75.0;
static const double kFinalSize = 30.0;
static const List<Color> kBoxColors = [
Colors.red,
Colors.green,
Colors.yellow,
Colors.purple,
Colors.orange,
Colors.grey,
];
ScrollController _scrollController = new ScrollController();
@override
void initState()
_scrollController.addListener(()
setState(() /* State being set is the Scroll Controller's offset */ );
);
@override
void dispose()
_scrollController.dispose();
Widget build(BuildContext context)
Widget buildAppBarBottom(double size)
double t = (size - kInitialSize) / (kFinalSize - kInitialSize);
const double initialContainerHeight = 2 * kInitialSize;
const double finalContainerHeight = kFinalSize;
return Container(
height: lerpDouble(initialContainerHeight, finalContainerHeight, t),
child: LayoutBuilder(
builder: (context, constraints)
List<Widget> stackChildren = [];
for (int i = 0; i < 6; i++)
Offset offset = getInterpolatedOffset(i, constraints, t);
stackChildren.add(Positioned(
left: offset.dx,
top: offset.dy,
child: buildSizedBox(size, kBoxColors[i]),
));
return Stack(children: stackChildren);
,
),
);
Offset getInterpolatedOffset(int index, BoxConstraints constraints, double t)
Curve curve = Curves.linear;
double curveT = curve.transform(t);
Offset a = getOffset(index, constraints, kInitialSize, 3);
Offset b = getOffset(index, constraints, kFinalSize, 6);
return Offset(
lerpDouble(a.dx, b.dx, curveT),
lerpDouble(a.dy, b.dy, curveT),
);
Offset getOffset(int index, BoxConstraints constraints, double size, int columns)
int x = index % columns;
int y = index ~/ columns;
double horizontalMargin = (constraints.maxWidth - size * columns) / 2;
return Offset(horizontalMargin + x * size, y * size);
Widget buildSizedBox(double size, Color color)
return Container(
height: size,
width: size,
color: color,
);
New contributor
You could use a Stack together with Positioned widgets to position the ShrinkableBoxes as you need. Since what controls the animation is the scroll offset, you don't need to use animated widgets or an animation controller or something like it. Here's a working example which calculates the positions by linearly interpolating the initial and final position of the boxes (you can get different animation paths by changing the Curves.linear to other curves):
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
void main()
runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget
@override
State createState() => HomeState();
class HomeState extends State<Home>
static const double kExpandedHeight = 300.0;
static const double kInitialSize = 75.0;
static const double kFinalSize = 30.0;
static const List<Color> kBoxColors = [
Colors.red,
Colors.green,
Colors.yellow,
Colors.purple,
Colors.orange,
Colors.grey,
];
ScrollController _scrollController = new ScrollController();
@override
void initState()
_scrollController.addListener(()
setState(() /* State being set is the Scroll Controller's offset */ );
);
@override
void dispose()
_scrollController.dispose();
Widget build(BuildContext context)
Widget buildAppBarBottom(double size)
double t = (size - kInitialSize) / (kFinalSize - kInitialSize);
const double initialContainerHeight = 2 * kInitialSize;
const double finalContainerHeight = kFinalSize;
return Container(
height: lerpDouble(initialContainerHeight, finalContainerHeight, t),
child: LayoutBuilder(
builder: (context, constraints)
List<Widget> stackChildren = [];
for (int i = 0; i < 6; i++)
Offset offset = getInterpolatedOffset(i, constraints, t);
stackChildren.add(Positioned(
left: offset.dx,
top: offset.dy,
child: buildSizedBox(size, kBoxColors[i]),
));
return Stack(children: stackChildren);
,
),
);
Offset getInterpolatedOffset(int index, BoxConstraints constraints, double t)
Curve curve = Curves.linear;
double curveT = curve.transform(t);
Offset a = getOffset(index, constraints, kInitialSize, 3);
Offset b = getOffset(index, constraints, kFinalSize, 6);
return Offset(
lerpDouble(a.dx, b.dx, curveT),
lerpDouble(a.dy, b.dy, curveT),
);
Offset getOffset(int index, BoxConstraints constraints, double size, int columns)
int x = index % columns;
int y = index ~/ columns;
double horizontalMargin = (constraints.maxWidth - size * columns) / 2;
return Offset(horizontalMargin + x * size, y * size);
Widget buildSizedBox(double size, Color color)
return Container(
height: size,
width: size,
color: color,
);
New contributor
New contributor
answered Mar 18 at 8:06
Luis Fernando TrivelattoLuis Fernando Trivelatto
262
262
New contributor
New contributor
This is exactly what i wanted! How were you able to figure this out? This is a pretty complex piece of code. I would like to learn animations like this for myself as well.
– smbl
Mar 19 at 3:26
@smbl Thanks! I guess I've had a fair share of struggles with animations in Flutter hehe. Have you checked out the Animations section of the Flutter website? While it explains how to do more complex animations, you might also want to check out the implicitly animated widgets, which are still powerful and simpler to use, such as AnimatedContainer: flutter.dev/docs/development/ui/widgets/animation
– Luis Fernando Trivelatto
Mar 19 at 20:33
add a comment |
This is exactly what i wanted! How were you able to figure this out? This is a pretty complex piece of code. I would like to learn animations like this for myself as well.
– smbl
Mar 19 at 3:26
@smbl Thanks! I guess I've had a fair share of struggles with animations in Flutter hehe. Have you checked out the Animations section of the Flutter website? While it explains how to do more complex animations, you might also want to check out the implicitly animated widgets, which are still powerful and simpler to use, such as AnimatedContainer: flutter.dev/docs/development/ui/widgets/animation
– Luis Fernando Trivelatto
Mar 19 at 20:33
This is exactly what i wanted! How were you able to figure this out? This is a pretty complex piece of code. I would like to learn animations like this for myself as well.
– smbl
Mar 19 at 3:26
This is exactly what i wanted! How were you able to figure this out? This is a pretty complex piece of code. I would like to learn animations like this for myself as well.
– smbl
Mar 19 at 3:26
@smbl Thanks! I guess I've had a fair share of struggles with animations in Flutter hehe. Have you checked out the Animations section of the Flutter website? While it explains how to do more complex animations, you might also want to check out the implicitly animated widgets, which are still powerful and simpler to use, such as AnimatedContainer: flutter.dev/docs/development/ui/widgets/animation
– Luis Fernando Trivelatto
Mar 19 at 20:33
@smbl Thanks! I guess I've had a fair share of struggles with animations in Flutter hehe. Have you checked out the Animations section of the Flutter website? While it explains how to do more complex animations, you might also want to check out the implicitly animated widgets, which are still powerful and simpler to use, such as AnimatedContainer: flutter.dev/docs/development/ui/widgets/animation
– Luis Fernando Trivelatto
Mar 19 at 20:33
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55056721%2fanimating-widget-positions-as-the-screen-scrolls-in-flutter-gif-included%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown