I’m not good at animation but want to add animation which is like , there are 4 alphabets letters “B”, “C” , “D” and “E” which should animate from their 4 axis towards to the center and make a logo at center then when animation get complete, social buttons should animtate from the bottom that’s all I want to implements.
I’m going to add screens which make my concept more clear, what I’m trying to say :
First view
second view
Code for simple for showing Splash image
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return _SplashScreenState();
}
}
class _SplashScreenState extends State<SplashScreen> {
Timer? timer;
@override
void initState() {
super.initState();
navigatePage();
}
void navigatePage() async {
timer = Timer(const Duration(seconds: 2), () async {
isLoggedIn
? Navigator.pushReplacementNamed(context, "home")
: Navigator.pushReplacementNamed(context, "login");
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xffF7F8F8),
body: Image.asset(
'assets/images/splash.png',
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
));
}
@override
void dispose() {
timer?.cancel();
super.dispose();
}
}
You can play with AnimatedPositioned
and AnimatedRotation
:
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool animated = false;
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
animated = !animated;
});
},
),
body: Stack(
children: [
AnimatedPositioned(
top: animated
? MediaQuery.of(context).size.height * .50
: MediaQuery.of(context).size.height * .75,
right: animated
? MediaQuery.of(context).size.width * .100
: MediaQuery.of(context).size.width * .50,
duration: const Duration(seconds: 3),
child: AnimatedRotation(
duration: const Duration(seconds: 3),
turns: animated ? 0.3 : 0.45,
child: container(color: Colors.green),
),
),
AnimatedPositioned(
top: animated
? MediaQuery.of(context).size.height * .25
: MediaQuery.of(context).size.height * .50,
right: animated
? MediaQuery.of(context).size.width * .25
: MediaQuery.of(context).size.width * .50,
duration: const Duration(seconds: 3),
child: AnimatedRotation(
duration: const Duration(seconds: 3),
turns: animated ? 0.3 : 0.1,
child: container(color: Colors.blue),
),
),
AnimatedPositioned(
top: animated
? MediaQuery.of(context).size.height * .75
: MediaQuery.of(context).size.height * .15,
right: animated
? MediaQuery.of(context).size.width * .50
: MediaQuery.of(context).size.width * .25,
duration: const Duration(seconds: 3),
child: AnimatedRotation(
duration: const Duration(seconds: 3),
turns: animated ? -0.3 : 0.13,
child: container(color: Colors.yellow),
),
),
],
),
);
}
Widget container({Color color = Colors.grey}) {
return Container(
height: 50,
width: 50,
color: color,
);
}
}
I created the animation simply using Hero
, focused on the animation is BETWEEN PAGES.
Please refer to the example for not wearing fancy colours or designs.
import 'package:flutter/material.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@override
State<StatefulWidget> createState() {
return _SplashScreenState();
}
}
class _SplashScreenState extends State<SplashScreen> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
transitionDuration: const Duration(seconds: 1),
pageBuilder: (context, animation, secondaryAnimation) => const LoginPage(),
),
);
},
child: const Scaffold(
backgroundColor: Color(0xffF7F8F8),
body: Stack(
children: [
Align(child: MainLogoItem()),
Positioned(
top: 150,
child: LogoItem('B'),
),
Positioned(
bottom: 50,
left: 30,
child: LogoItem('C'),
),
Positioned(
right: 20,
bottom: 130,
child: LogoItem('D'),
),
Positioned(
top: 30,
right: 70,
child: LogoItem('E'),
),
],
),
),
);
}
}
class LoginPage extends StatelessWidget {
const LoginPage({super.key});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: const Scaffold(
backgroundColor: Color(0xffF7F8F8),
body: Center(child: Logo()),
),
);
}
}
class Logo extends StatelessWidget {
const Logo({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: const [
BoxShadow(
color: Colors.grey,
blurRadius: 5,
spreadRadius: 1,
),
],
),
child: const Stack(
children: [
Align(child: MainLogoItem()),
Positioned(
left: 20,
top: 10,
child: LogoItem('B'),
),
Positioned(
bottom: 10,
left: 15,
child: LogoItem('C'),
),
Positioned(
right: 10,
bottom: 10,
child: LogoItem('D'),
),
Positioned(
top: -10,
right: 30,
child: LogoItem('E'),
),
],
),
);
}
}
class MainLogoItem extends StatelessWidget {
const MainLogoItem({
super.key,
});
@override
Widget build(BuildContext context) {
return const LogoItem('A', fontSize: 50);
}
}
class LogoItem extends StatelessWidget {
final String alphabet;
final double? fontSize;
const LogoItem(
this.alphabet, {
super.key,
this.fontSize,
});
@override
Widget build(BuildContext context) {
return Hero(
tag: 'LogoItem $alphabet',
child: Text(
alphabet,
style: TextStyle(
color: Colors.black,
decoration: TextDecoration.none,
fontSize: fontSize ?? 30,
fontWeight: FontWeight.bold,
height: 0,
),
),
);
}
}
How to test
- Paste & copy the codes.
- Add
SplashScreen
to your app. - Tap screen then it navigate you to
LoginPage
with animation. - Tap again to get back to
SpalshScreen
.
I did my best but I am pretty sure there must be a better solution.
I hope you get some hints from my code though.