Login Screen
Clean email + password login with form validation and loading state
View component →A clean animated splash screen that fades the app logo in, slides the wordmark up, and auto-navigates to the next screen after a short delay — all driven by a single AnimationController with staggered Interval curves. The perfect first frame for any Flutter app while it boots, checks auth, or loads config.
WHAT'S INCLUDED
USE CASES
PRO TIP
Do real startup work — auth check, remote config, cached-session read — inside initState and navigate when both the animation and the work have finished, rather than relying on a fixed Future.delayed. A hardcoded delay either feels slow on fast devices or cuts off work on slow ones; gating navigation on Future.wait of [animation, bootstrap] is smoother.
Copy this entire snippet into your Flutter project. No external packages required.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.white,
body: Center(
child: SplashScreen(
nextScreen: Scaffold(
backgroundColor: Colors.white,
body: Center(child: Text('Welcome!')),
),
),
),
),
);
}
}
class SplashScreen extends StatefulWidget {
final Widget nextScreen;
const SplashScreen({super.key, required this.nextScreen});
@override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
late final Animation<double> _logoFade;
late final Animation<Offset> _textSlide;
late final Animation<double> _textFade;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1400),
);
_logoFade = CurvedAnimation(
parent: _controller,
curve: const Interval(0.0, 0.6, curve: Curves.easeOut),
);
_textFade = CurvedAnimation(
parent: _controller,
curve: const Interval(0.4, 1.0, curve: Curves.easeOut),
);
_textSlide = Tween<Offset>(
begin: const Offset(0, 0.4),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _controller,
curve: const Interval(0.4, 1.0, curve: Curves.easeOutCubic),
));
_controller.forward();
Future.delayed(const Duration(milliseconds: 2500), () {
if (!mounted) return;
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => widget.nextScreen),
);
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF1D9E75),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FadeTransition(
opacity: _logoFade,
child: Container(
width: 96,
height: 96,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
),
child: const Icon(
Icons.bolt,
size: 56,
color: Color(0xFF1D9E75),
),
),
),
const SizedBox(height: 24),
FadeTransition(
opacity: _textFade,
child: SlideTransition(
position: _textSlide,
child: const Text(
'FlutterKit',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.w600,
letterSpacing: 0.5,
),
),
),
),
],
),
),
);
}
}
Clean email + password login with form validation and loading state
View component →Full name, email, password registration with confirm password validation
View component →Registration screen with role selection grid — Owner, Manager, or Employee
View component →