How to center the anchor point of a shape in Flutter? - flutter

I have a continer whose length and width are 0, but with the animation, I change its length and width to 200. The problem is that when it starts to grow, it grows from the bottom and does not grow from the middle. I want to know how to place its anchor point in the middle. Working with after effects, they will understand by seeing this image
For example, in the code below, the circle starts growing from the bottom, while I want it to start growing from the middle point of the circle:
class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin {
late Animation<double> width;
late AnimationController controller;
#override
void initState() {
super.initState();
controller =
AnimationController(duration: Duration(seconds: 2), vsync: this);
width = Tween<double>(begin: 0, end: 200).animate(controller);
width.addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(50),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
onPressed: () {
controller.forward();
},
child: Text('a')),
Container(
width: width.value,
height: width.value,
decoration:
BoxDecoration(shape: BoxShape.circle, color: Colors.black),
),
],
),
),
);
}
}

class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin {
late Animation<double> width;
late AnimationController controller;
Tween<double> animation = Tween<double>(begin: 0, end: 200);
#override
void initState() {
super.initState();
controller =
AnimationController(duration: Duration(seconds: 2), vsync: this);
width = animation.animate(controller);
width.addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(50),
child: Column(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
onPressed: () {
controller.forward();
},
child: Text('a'),
),
SizedBox(height: animation.end!-width.value/2),
Container(
width: width.value,
height: width.value,
decoration:
BoxDecoration(shape: BoxShape.circle, color: Colors.black),
),
],
),
),
);
}
}

I believe you have a positioning issue. I moved the circle a little bit and now it seems that it starts to grow from the center. Please let me know if this code fixes your issue:
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> with SingleTickerProviderStateMixin {
late Animation<double> width;
late AnimationController controller;
#override
void initState() {
super.initState();
controller = AnimationController(duration: Duration(seconds: 2), vsync: this);
width = Tween<double>(begin: 0, end: 200).animate(controller);
width.addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
controller.forward();
},
child: Text('a')),
AnimatedContainer(
width: width.value,
height: width.value,
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.black),
duration: controller.duration!,
),
],
),
),
);
}
}

Related

How to make a linear progress indicator with swing effect?

I want to make a progress bar that looks like this. If you look closely, the length of the indicator varies when it swings.
I tried to reuse the linear progress bar that flutter provides.
import 'package:flutter/material.dart';
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget>
with TickerProviderStateMixin {
late AnimationController controller;
#override
void initState() {
controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 5),
)..addListener(() {
setState(() {});
});
controller.repeat(reverse: true);
super.initState();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
LinearProgressIndicator(
value: controller.value,
),
],
),
),
);
}
}
And it looks like this.
You can follow this snippet. Run on dartPad
/// create ---- ProgressIndicator
///
/// ````
/// child: SizedBox(
/// height: 12,
/// child: CustomLinearProgressIndicator(
/// backgroundColor: Colors.white,
/// color: Colors.blue,
/// maxProgressWidth: 100,
/// ),
/// ),
/// ````
class CustomLinearProgressIndicator extends StatefulWidget {
const CustomLinearProgressIndicator({
Key? key,
this.color = Colors.blue,
this.backgroundColor = Colors.white,
this.maxProgressWidth = 100,
}) : super(key: key);
/// max width in center progress
final double maxProgressWidth;
final Color color;
final Color backgroundColor;
#override
State<CustomLinearProgressIndicator> createState() =>
_CustomLinearProgressIndicatorState();
}
class _CustomLinearProgressIndicatorState
extends State<CustomLinearProgressIndicator>
with SingleTickerProviderStateMixin {
late AnimationController controller =
AnimationController(vsync: this, duration: const Duration(seconds: 1))
..addListener(() {
setState(() {});
})
..repeat(reverse: true);
late Animation animation =
Tween<double>(begin: -1, end: 1).animate(controller);
#override
Widget build(BuildContext context) {
return ColoredBox(
color: widget.backgroundColor,
child: Align(
alignment: Alignment(animation.value, 0),
child: Container(
decoration: ShapeDecoration(
// play with BoxDecoration if you feel it is needed
color: widget.color,
shape: const StadiumBorder(),
),
// you can use animatedContainer, seems not needed
width: widget.maxProgressWidth -
widget.maxProgressWidth * (animation.value as double).abs(),
height: double.infinity,
),
),
);
}
}

How to create the following circular animation in flutter

Dark portion is continuously circulating.
Size of dark portion is proportional to amount of data loaded.
Example:- When 40% data loaded then the dark circulating part is 40% of circumference. When 60% data loaded then the dark circulating part is 60% of circumference. So on.
https://youtu.be/a4czRLK6ouE
Here is my attempt to create this animation:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: HomePage(),
),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
late final AnimationController controller;
double percent = 0.0;
// ** Addition in #mmcdon20 code - Start
changePercent() {
// 20 frame is enough to beat eye, that's why I used
// 50 refresh/second to keep animation smooth
Future.delayed(
const Duration(milliseconds: 20), // Adjust accordingly.
() {
setState(() {
percent += 0.005; // Adjust accordingly.
});
print('........................');
if (percent < 1) {
changePercent();
}
},
);
}
// ** Addition in #mmcdon20 code - End
#override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)
..animateTo(1)
..repeat();
// ** Addition in #mmcdon20 code - Start
changePercent();
// ** Addition in #mmcdon20 code - End
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CustomProgressIndicator(
value: percent,
color: Colors.orange,
controller: controller,
width: 200,
height: 200,
strokeWidth: 10,
// curve: Curves.slowMiddle, // ** Eliminationated from #mmcdon20 code
),
// ** Eliminationated from #mmcdon20 code - Start
// Slider(
// value: percent,
// onChanged: (v) {
// setState(() {
// percent = v;
// });
// },
// ),
// ** Eliminationated from #mmcdon20 code - End
],
),
);
}
}
class CustomProgressIndicator extends StatelessWidget {
const CustomProgressIndicator({
Key? key,
required this.color,
required this.value,
required this.controller,
required this.width,
required this.height,
required this.strokeWidth,
this.curve = Curves.linear,
}) : super(key: key);
final Color color;
final double value;
final AnimationController controller;
final double width;
final double height;
final double strokeWidth;
final Curve curve;
#override
Widget build(BuildContext context) {
return RotationTransition(
turns: CurvedAnimation(
parent: controller,
curve: curve,
),
child: SizedBox(
width: width,
height: height,
child: CircularProgressIndicator(
strokeWidth: strokeWidth,
color: color,
backgroundColor: color.withOpacity(.2),
value: value,
),
),
);
}
}
1st Add this:
dependencies:
percent_indicator: ^3.4.0
Then Example:
import 'package:flutter/material.dart';
import 'package:percent_indicator_example/sample_circular_page.dart';
import 'package:percent_indicator_example/sample_linear_page.dart';
void main() {
runApp(MaterialApp(home: Scaffold(body: SamplePage())));
}
class SamplePage extends StatefulWidget {
#override
_SamplePageState createState() => _SamplePageState();
}
class _SamplePageState extends State<SamplePage> {
void _openPage(Widget page) {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => page,
),
);
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
color: Colors.blueAccent,
child: Text("Circular Library"),
onPressed: () => _openPage(SampleCircularPage()),
),
Padding(
padding: EdgeInsets.all(20.0),
),
MaterialButton(
color: Colors.blueAccent,
child: Text("Linear Library"),
onPressed: () => _openPage(SampleLinearPage()),
),
],
),
),
);
}
}

Change scrollView offset without callback listener

I want to change scrollView's offset with code so I use ScrollController:
ScrollController _controller;
_controller.addListener(() {
print('call listener');
});
My way to change offset:
_controller.jumpTo(200);
it will callback listener once.
or
_controller.animateTo(200, duration: Duration(milliseconds: 1), curve: Curves.linear);
it will callback listener, too.
I wonder is there any way to change scrollView offset without callback listener.
Here is all my code and you can coppy and test:
import 'package:flutter/material.dart';
class SingleChildScrollViewDemoPage extends StatefulWidget {
SingleChildScrollViewDemoPage({Key key}) : super(key: key);
#override
_SingleChildScrollViewDemoPageState createState() =>
_SingleChildScrollViewDemoPageState();
}
class _SingleChildScrollViewDemoPageState
extends State<SingleChildScrollViewDemoPage> {
ScrollController _controller;
#override
void initState() {
super.initState();
_controller = ScrollController();
_controller.addListener(() {
print('call listener');
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('SingleChildScrollView')),
body: SingleChildScrollView(
controller: _controller,
child: Column(
children: [
RaisedButton(
child: Text('change offset'),
onPressed: () {
//_controller.jumpTo(200);
_controller.animateTo(200,
duration: Duration(milliseconds: 1), curve: Curves.linear);
},
),
Container(
width: 375,
height: 200,
color: Colors.red,
),
SizedBox(height: 30),
Container(
width: 375,
height: 3000,
color: Colors.green,
),
],
),
),
);
}
}

How to animate the swap of 2 items in a Row?

I want to make something very simple. There's a Row with 2 widgets. When I press a button, they swap orders. I want this order swap to be animated.
I've loked at AnimatedPositioned but it requires a Stack. What would be the best way of doing such thing?
I thought Animating position across row cells in Flutter answered this but it's another different problem
You can easily animate widgets in a Row with SlideAnimation. Please see the code below or you may directly run the code on DartPad https://dartpad.dev/e5d9d2c9c6da54b3f76361eac449ce42 Just tap on the colored box to swap their positions with an slide animation.
SlideAnimation
Animates the position of a widget relative to its normal position.
The translation is expressed as an Offset scaled to the child's size.
For example, an Offset with a dx of 0.25 will result in a horizontal
translation of one quarter the width of the child.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
AnimationController _controller;
List<Animation<Offset>> _offsetAnimation;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
_offsetAnimation = List.generate(
2,
(index) => Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: Offset(index == 0 ? 1 : -1, 0.0),
).animate(_controller),
);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
void _animate() {
_controller.status == AnimationStatus.completed
? _controller.reverse()
: _controller.forward();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Flutter Demo Row Animation")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
BoxWidget(
callBack: _animate,
text: "1",
color: Colors.red,
position: _offsetAnimation[0],
),
BoxWidget(
callBack: _animate,
text: "2",
color: Colors.blue,
position: _offsetAnimation[1],
)
],
),
RaisedButton(
onPressed: _animate,
child: const Text("Swap"),
)
],
),
),
);
}
}
class BoxWidget extends StatelessWidget {
final Animation<Offset> position;
final Function callBack;
final String text;
final Color color;
const BoxWidget(
{Key key, this.position, this.callBack, this.text, this.color})
: super(key: key);
#override
Widget build(BuildContext context) {
return SlideTransition(
position: position,
child: GestureDetector(
onTap: () => callBack(),
child: Container(
margin: const EdgeInsets.all(10),
height: 50,
width: 50,
color: color,
child: Center(
child: Container(
height: 20,
width: 20,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
child: Center(child: Text(text)),
),
),
),
),
);
}
}

animate widgets based on condition in scaffold body

I have a widget, with a scaffold. His body is x widget, how do I animate in the y widget on the body instead of the x widget?
The widgets are like:
Scaffold(
body: condition ? X() : Y(),
)
When the condition goes from true to false or false to true, I want the Y or X widget to animate in. How can I do this?
You can change the Offset values to get your desired result
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test>
with SingleTickerProviderStateMixin {
bool condition;
AnimationController _controller;
Animation<Offset> _offsetAnimation;
#override
void initState() {
condition = false;
_controller = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
_offsetAnimation =
Tween<Offset>(begin: Offset(0.0, -5.0), end: Offset.zero)
.animate(CurvedAnimation(
curve: Curves.linear,
parent: _controller,
));
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: InkWell(
onTap: () {
setState(() {
condition = true;
});
_controller.forward();
},
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.red,
width: 200,
height: 200,
),
if (condition)
SlideTransition(
position: _offsetAnimation,
child: Container(
color: Colors.green,
width: 100,
height: 100,
),
),
],
),
),
),
);
}
}