I have the following code in place to animate a Positioned widgets, position, when a pan ends. However, it doesn't animate.
Initialising AnimationController and variables:
AnimationController nodesListAnimationController;
Animation<double> nodesListAnimation;
double nodesListOffsetY = 0.0; //widget default offset (will be large, but acts like 0.0)
double nodesListDragOffsetY = 0.0; //how far we have moved the widget from default offset (nodesListOffsetY)
double nodesListTouchOffset = 0.0; //the initial touch when drag begins
final double nodesListHeight = 350.0; //widget height
@override
void initState() {
super.initState();
nodesListAnimationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 350),
)
..addListener((){
setState(() {
});
});
}
Build function; See the Positioned widget. I can drag this up and down within the bound I have created using the panning callbacks on GestureDetector.
When the pan ends, I want to animate the Positioned widget back to a given position. Currently, no animation occurs.
@override
Widget build(BuildContext context) {
nodesListOffsetY = MediaQuery.of(context).size.width + 110.0;
AppBar appBar = AppBar(
...
);
return Scaffold(
appBar: appBar,
backgroundColor: Colors.black,
body: Stack(
children: <Widget>[
Column(
children: <Widget>[
cameraWidget(),
cameraControls(),
],
),
Positioned(
left: 0.0,
top: nodesListAnimationController.isAnimating ? nodesListAnimation.value : nodesListOffsetY + nodesListDragOffsetY,
width: MediaQuery.of(context).size.width,
height: nodesListHeight,
child: GestureDetector(
onPanStart: (dragDetails) {
nodesListTouchOffset = (dragDetails.globalPosition.dy - appBar.preferredSize.height) - nodesListOffsetY - nodesListDragOffsetY;
},
onPanUpdate: (dragDetails) {
setState(() {
double newDragOffset = (dragDetails.globalPosition.dy - nodesListOffsetY) - appBar.preferredSize.height - nodesListTouchOffset;
//allow it only to move up if is clips off screen, otherwise upper limit not needed
double nodesListVisible = ((MediaQuery.of(context).size.height - appBar.preferredSize.height) - nodesListOffsetY);
bool isClipping = nodesListVisible < nodesListHeight ? true : false;
double upperLimit = 0.0;
if (isClipping) upperLimit = -(nodesListHeight - nodesListVisible);
//limit drag bounds. don't drag too high or low.
if (newDragOffset < upperLimit) newDragOffset = upperLimit;
else if (newDragOffset > 0) newDragOffset = 0.0;
else nodesListDragOffsetY = newDragOffset;
});
},
onPanEnd: (dragDetails) {
double currentPos = (nodesListOffsetY + nodesListDragOffsetY);
nodesListAnimation = Tween(begin: currentPos, end: nodesListOffsetY).animate(nodesListAnimationController);
nodesListAnimationController.forward(from: currentPos);
nodesListAnimation.addStatusListener((state) {
print(nodesListAnimation.value);
});
},
child: nodesList(),
),
),
],
));
}
Late to the party, but your issue is because of:
nodesListAnimationController.forward(from: currentPos)
Whose from is incorrectly accepting a value outside of 0.0-1.0. So you should probably change it to just controller.forward()
This isn’t well documented, but forward’s from is meant to accept values from 0.0-1.0, or more specifically, if set, then the range provided by lowerBound and upperBound (with few exceptions). (you can also think of it as 0-100%). It is not meant to accept the value range from the Tween’s begin and end, nor is it aware of that range.
https://api.flutter.dev/flutter/animation/AnimationController-class.html
By default, an AnimationController linearly produces values that range from 0.0 to 1.0
https://flutter.dev/docs/development/ui/animations/overview#addstatuslistener
An animation might then run forward (e.g., from 0.0 to 1.0)
(And I can verify that after I changed your code to use just .forward(), I was able to see it animate)
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