I want to add something cool to my age input screen in Flutter, and the main way I want to do that is by having a image grow when the age slider is increased, and shrink when the age slider is decreased. Its a pretty simple animation that I have no idea how to implement, and it would be greatly appreciated if someone answered this question. Here is a screenshot of my current age screen (there is a big space for the growing image): (check below image), and the code for the screenshot. Thanks!
EDIT: A BIG bonus that would be super helpful for me is to make the animation change from a kid to an adult to an elder as the user increases the slider. So the image starts off as a kid, gets bigger and the image changes to an adult, and then shrinks a little bit and changes to an elderly man/woman. If this is pulled off I will be super greatful. Thanks again!
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:workout_app/Screens/Components/Sign_Up_Screens/screen1.dart';
import 'package:workout_app/Screens/Components/Sign_Up_Screens/screen3.dart';
class screen2 extends StatefulWidget {
@override
State<StatefulWidget> createState() => Main();
}
class Main extends State<screen2> {
void returnScreen(context) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => screen1(),
),
);
}
@override
void initState() {
loadData();
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
int age = 10;
bool nextValid = false;
void toast(String text) {
final scaffold = ScaffoldMessenger.of(context);
scaffold.showSnackBar(
SnackBar(
width: MediaQuery.of(context).size.width * .5,
behavior: SnackBarBehavior.floating,
content: Text(text),
duration: const Duration(seconds: 1),
elevation: 10,
),
);
}
void submitData() async {
if(nextValid == false) {
toast('Please input your age');
return;
}
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setInt('age', age);
Navigator.of(context).pushReplacement(
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => SingleSelectListViewWithLogo(items : ['Tone Up - You want visible muscles with as little mass as possible and a low body fat percentage', 'Bulk Up - You want large, defined muscles, with a low percentage of body fat', 'Get Jacked - You want to lift an insane amount of weight and don't care about body fat or muscle definition']),
),
);
}
void loadData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
try {
int? x = prefs.getInt('age');
print(x);
if(x != null) {
setState(() => {age = x, nextValid = true});
}
} catch (Exception){
//continue;
}
}
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Material(
child: Scaffold(
body:
Container (
decoration: const BoxDecoration(color: Color.fromARGB(255, 46, 46, 46)),
height: size.height,
width: double.infinity,
child: Stack(
children: <Widget> [
Positioned (
top: size.height * .34,
height: size.height * .6,
width: size.width * .9,
left: size.width * .05,
child: Container (
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Color.fromARGB(255, 73, 73, 73),
),
),
),
Positioned(
top: size.height * .06,
left: size.width * .03,
child: InkWell(
onTap: () {
returnScreen(context);
},
child: Image.asset(
alignment: Alignment.topLeft,
"assets/images/whitebackarrow.png",
width: size.width * .07,
),
),
),
Positioned(
top: size.height * .09,
left: size.width * .35,
child: const Text(
style: TextStyle(fontSize: 50, color: Color.fromARGB(255, 255, 255, 255), fontWeight: FontWeight.bold),
'Next,'
)
),
Positioned(
top: size.height * .19,
left: size.width * .06,
child: const Text(
style: TextStyle(fontSize: 25, color: Color.fromARGB(255, 255, 255, 255)),
'Lets customize your workout!'
)
),
Positioned(
top: size.height * .38,
left: size.width * .13,
child: const Text(
style: TextStyle(fontSize: 25, color: Color.fromARGB(255, 0, 0, 0), fontWeight: FontWeight.bold),
'What's your current age?'
)
),
Positioned (
top: size.height * .7,
left: size.width * .1,
child: SliderTheme(
data: const SliderThemeData(
trackHeight: 30,
inactiveTrackColor: Color.fromARGB(255, 160, 160, 160),
activeTrackColor: Color.fromARGB(255, 40, 39, 39),
thumbColor: Colors.black,
disabledActiveTrackColor: Colors.black,
disabledInactiveTrackColor: Colors.black12,
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 25.0),
),
child: Container (
width: size.width * .8,
child: Slider(
label: "Select Age",
value: age.toDouble(),
onChanged: (value) {
setState(() {
age = value.toInt();
nextValid = true;
});
},
min: 10,
max: 99,
)
)
)
),
Positioned (
top: size.height * .605,
left: size.width * .25,
child: Text(
age.toString(),
style: const TextStyle(
fontSize: 50.0,
fontWeight: FontWeight.bold
),
),
),
Positioned (
top: size.height * .64,
left: size.width * .42,
child: const Text (
'years old',
style: TextStyle(
fontSize: 25.0,
),
)
),
Positioned(
top: size.height * .825,
left: size.width * .1,
child: SizedBox(
width: size.width * .8,
height: size.height * .08,
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(!nextValid ? Color.fromRGBO(69, 75, 85, 1) : Color.fromARGB(255, 23, 100, 22)),
),
child: const Text('Continue',
style: TextStyle(fontSize: 20),
),
onPressed: () async {
submitData();
},
),
),
),
]
)
)
)
);
}
}
2
Answers
According to your code, you can just have an
Image.asset
with theheight
property. Use theage
state as the height of the image. You can do simple maths here where you can multiply the age with some number to fit the image to your liking.To animate the image I’ll check it off with an
AnimatedContainer
but in this case you’d need to rework the above solution to this:Edit: Just to add a bit more details:
AnimatedContainer
lets you animate yourContainer
s with the given property (height
,width
,decoration
,color
, etc.). When you insert a state variable (in this case theage
variable) as the input to one of these parameters, theAnimatedContainer
will automatically animate its property based on the input changes. It requiresDuration
in order to know how long the animation will take to run. You can additionally add fancier animations than just linear ones by including thecurve
property.To learn more about animations please refer to Introduction to animations.
To learn more about
AnimatedContainer
please refer to AnimatedContainer classTo learn more about
Curves
please refer to Curves classLittle late to answer. I did following to achieve the same.
Demo: https://youtube.com/shorts/CyymV-GQvj4?feature=share
PS: I know there is already an accepted answer. I thought why not share it here as the solution is ready.