Enhance splash screen with improved animations and loading indicator; update logo size and message for better visibility

This commit is contained in:
Vaibhav Surve 2025-11-29 12:34:30 +05:30
parent 37ce612fca
commit 3ad48016f3

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// Assuming 'package:on_field_work/images.dart' correctly provides 'Images.logoDark'
import 'package:on_field_work/images.dart'; import 'package:on_field_work/images.dart';
class SplashScreen extends StatefulWidget { class SplashScreen extends StatefulWidget {
@ -8,8 +9,9 @@ class SplashScreen extends StatefulWidget {
const SplashScreen({ const SplashScreen({
super.key, super.key,
this.message, this.message =
this.logoSize = 120, 'GET WORK DONE, ANYWHERE.', // Default message for a modern look
this.logoSize = 150, // Slightly larger logo
this.backgroundColor = Colors.white, this.backgroundColor = Colors.white,
}); });
@ -20,20 +22,59 @@ class SplashScreen extends StatefulWidget {
class _SplashScreenState extends State<SplashScreen> class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late AnimationController _controller; late AnimationController _controller;
late Animation<double> _animation; // Animation for the logo's vertical float effect
late Animation<double> _floatAnimation;
// Animation for logo's initial scale-in
late Animation<double> _scaleAnimation;
// Animation for logo and text fade-in
late Animation<double> _opacityAnimation;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_controller = AnimationController( _controller = AnimationController(
duration: const Duration(seconds: 1), duration:
const Duration(seconds: 3), // Longer duration for complex sequence
vsync: this, vsync: this,
)..repeat(reverse: true);
_animation = Tween<double>(begin: 0.0, end: 8.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
); );
// Initial scale-in: from 0.0 to 1.0 (happens in the first 40% of the duration)
_scaleAnimation = Tween<double>(begin: 0.5, end: 1.0).animate(
CurvedAnimation(
parent: _controller,
curve:
const Interval(0.0, 0.4, curve: Curves.easeOutBack), // Bouncy start
),
);
// Overall fade-in: from 0.0 to 1.0 (happens in the first 50% of the duration)
_opacityAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.0, 0.5, curve: Curves.easeIn),
),
);
// Floating effect: from 0.0 to 1.0 (loops repeatedly after initial animations)
_floatAnimation = Tween<double>(begin: -8.0, end: 8.0).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
),
);
// Start the complex animation sequence
_controller.forward().then((_) {
// After the initial scale/fade, switch to repeating the float animation
if (mounted) {
_controller.repeat(
min: 0.4, // Start repeat from the float interval
max: 1.0,
reverse: true,
);
}
});
} }
@override @override
@ -42,79 +83,73 @@ class _SplashScreenState extends State<SplashScreen>
super.dispose(); super.dispose();
} }
Widget _buildAnimatedDots() { // A simple, modern custom progress indicator
return Row( Widget _buildProgressIndicator() {
mainAxisAlignment: MainAxisAlignment.center, return SizedBox(
children: List.generate(3, (index) { width: 60,
return AnimatedBuilder( child: LinearProgressIndicator(
animation: _animation, backgroundColor: Colors.blueAccent.withOpacity(0.2),
builder: (context, child) { valueColor: const AlwaysStoppedAnimation<Color>(Colors.blueAccent),
double opacity;
if (index == 0) {
opacity = (0.3 + _animation.value / 8).clamp(0.0, 1.0);
} else if (index == 1) {
opacity = (0.3 + (_animation.value / 8)).clamp(0.0, 1.0);
} else {
opacity = (0.3 + (1 - _animation.value / 8)).clamp(0.0, 1.0);
}
return Container(
margin: const EdgeInsets.symmetric(horizontal: 4),
width: 10,
height: 10,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(opacity),
shape: BoxShape.circle,
), ),
); );
},
);
}),
);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: widget.backgroundColor, backgroundColor: widget.backgroundColor,
body: SafeArea( // Full screen display, no SafeArea needed for a full bleed splash
child: Center( body: Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// Logo with slight bounce animation // Animated Logo (Scale, Opacity, and Float)
ScaleTransition( FadeTransition(
scale: Tween(begin: 0.8, end: 1.0).animate( opacity: _opacityAnimation,
CurvedAnimation( child: AnimatedBuilder(
parent: _controller, animation: _floatAnimation,
curve: Curves.easeInOut, builder: (context, child) {
), return Transform.translate(
), offset: Offset(0, _floatAnimation.value),
child: ScaleTransition(
scale: _scaleAnimation,
child: SizedBox( child: SizedBox(
width: widget.logoSize, width: widget.logoSize,
height: widget.logoSize, height: widget.logoSize,
// Replace with your actual logo image widget
child: Image.asset(Images.logoDark), child: Image.asset(Images.logoDark),
), ),
), ),
);
},
),
),
const SizedBox(height: 20), const SizedBox(height: 30),
// Text message
// Text Message (Fades in slightly after logo)
if (widget.message != null) if (widget.message != null)
Text( FadeTransition(
opacity: _opacityAnimation,
child: Text(
widget.message!, widget.message!,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: const TextStyle( style: TextStyle(
fontSize: 18, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w500,
color: Colors.black87, color: Colors.grey.shade700,
letterSpacing: 1.2,
), ),
), ),
const SizedBox(height: 30), ),
// Animated loading dots
_buildAnimatedDots(), const SizedBox(height: 40),
// Modern Loading Indicator
_buildProgressIndicator(),
], ],
), ),
), ),
),
); );
} }
} }