https://www.youtube.com/watch?v=iWsfGf_UEXE&t=0s
➜ login_flutter_app cd packages/
➜ packages flutter create --template package auth_repository
Splash.mp4
dependencies:
flutter_native_splash: ^2.2.19
flutter_native_splash:
color: "#f7f6f1"
color_dark: "#272727"
image: assets/images/splash_images/splash-screen-image.png
image_dark: assets/images/splash_images/splash-screen-image.png
android_12:
background_color: "#f7f6f1"
background_color_dark: "#272727"
foreground_color: "#f7f6f1"
foreground_color_dark: "#272727"
image: assets/images/splash_images/splash-screen-image.png
image_dark: assets/images/splash_images/splash-screen-image.png
➜ login_flutter_app git:(main) ✗ flutter pub run flutter_native_splash:crea
Simulator.Screen.Recording.-.iOS14.-.2023-05-21.at.16.42.52.mp4
splash_screen.dart
class SplashScreen extends StatelessWidget {
SplashScreen({super.key});
final splashController = Get.put(SplashScreenController());
@override
Widget build(BuildContext context) {
splashController.startAnimation();
return Scaffold(
body: Stack(
children: [
Obx(() => AnimatedPositioned(
duration: const Duration(milliseconds: 1600),
top: splashController.animate.value ? 0 : -30,
left: splashController.animate.value ? 0 : -30,
child: const Image(
image: AssetImage(
tSplashTopIcon,
),
),
),
),
Obx(() => AnimatedPositioned(
duration: const Duration(milliseconds: 1600),
top: 80,
left: splashController.animate.value ? tDefaultSize : -80,
child: AnimatedOpacity(
duration: const Duration(milliseconds: 400),
opacity: splashController.animate.value ? 1 : 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tAppName,
style: Theme.of(context).textTheme.headlineLarge,
),
Text(
tAppTagLine,
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
),
),
Obx(() => AnimatedPositioned(
duration: const Duration(milliseconds: 2400),
bottom: splashController.animate.value ? 100 : 0,
child: const Image(
image: AssetImage(
tSplashImage,
),
),
),
),
Obx(() => AnimatedPositioned(
duration: const Duration(milliseconds: 2400),
bottom: splashController.animate.value ? 40 : 0,
right: tDefaultSize,
child: Container(
width: tSplashContainerSize,
height: tSplashContainerSize,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
color: tPrimaryColor,
),
),
),
),
],
),
);
}
}
splash_controller.dart
import 'package:get/get.dart';
import 'package:login_flutter_app/src/features/authentication/screens/authentications/screens/welcome/welcome/welcome_screen.dart';
class SplashScreenController extends GetxController {
static SplashScreenController get find => Get.find();
RxBool animate = false.obs;
Future startAnimation() async {
await Future.delayed(const Duration(milliseconds: 500));
animate.value = true;
await Future.delayed(const Duration(milliseconds: 5000));
Get.to(const WelcomeScreen());
//Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => const WelcomeScreen()));
}
}
lib/main.dart
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
Simulator.Screen.Recording.-.iOS14.-.2023-05-21.at.20.40.59.mp4
onboarding_screen.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:liquid_swipe/liquid_swipe.dart';
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import '../../controllers/on_boarding_controller.dart';
class OnBoaringScreen extends StatelessWidget {
OnBoaringScreen({super.key});
@override
Widget build(BuildContext context) {
final obController = OnBoardingConroller();
return Scaffold(
body: Stack(
alignment: Alignment.center,
children: [
LiquidSwipe(
pages: obController.pages,
liquidController: obController.controller,
onPageChangeCallback: obController.onPageChangeCallback,
slideIconWidget: const Icon(Icons.arrow_back_ios),
enableSideReveal: true,
),
Positioned(
bottom: 80.0,
child: OutlinedButton(
onPressed: obController.animateToNextSlide,
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
side: const BorderSide(color: Colors.black26),
shape: const CircleBorder(),
padding: const EdgeInsets.all(10),
),
child: Container(
padding: const EdgeInsets.all(20.0),
decoration: const BoxDecoration(
color: Color(0xff272727), shape: BoxShape.circle),
child: const Icon(Icons.arrow_forward_ios),
),
),
),
Positioned(
top: 50,
right: 20,
child: TextButton(
onPressed: obController.skip,
child: const Text(
"Skip",
style: TextStyle(
color: Colors.grey,
fontSize: 20.0,
),
),
),
),
Obx(
() => Positioned(
bottom: 30,
child: AnimatedSmoothIndicator(
activeIndex: obController.currentPage.value,
count: 3,
effect: const WormEffect(
activeDotColor: Color(0xff272727),
dotHeight: 5.0,
),
),
),
),
],
),
);
}
}
on_boarding_page_widget.dart
import 'package:flutter/material.dart';
import '../../../../constants/sizes.dart';
import '../../../../constants/text_strings.dart';
import '../../models/model_on_boarding.dart';
class OnboaringScreenWidget extends StatelessWidget {
const OnboaringScreenWidget({
super.key,
required this.model,
});
final OnBoardingModel model;
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Container(
padding: const EdgeInsets.all(tDefaultSize),
color: model.bgColor,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image(
image: AssetImage(
model.image,
),
height: size.height * 0.4,
),
Column(
children: [
Text(
model.title,
style: Theme.of(context).textTheme.headlineMedium,
),
Text(
model.subTitle,
textAlign: TextAlign.center,
),
],
),
Text(
model.counterText,
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(
height: 80.0,
),
],
),
);
}
}
on_boarding_controller.dart
import 'package:get/get.dart';
import 'package:liquid_swipe/PageHelpers/LiquidController.dart';
import '../../../constants/colors.dart';
import '../../../constants/image_strings.dart';
import '../../../constants/text_strings.dart';
import '../models/model_on_boarding.dart';
import '../screens/on_boarding/on_boarding_page_widget.dart';
class OnBoardingConroller extends GetxController {
final controller = LiquidController();
RxInt currentPage = 0.obs;
final pages = [
OnboaringScreenWidget(
model: OnBoardingModel(
image: tOnBoardingImage1,
title: tOnBoardingTitle1,
subTitle: tOnBoardingSubTitle1,
counterText: tOnBoardingCounter1,
bgColor: tOnBoardingPage1Color,
),
),
OnboaringScreenWidget(
model: OnBoardingModel(
image: tOnBoardingImage2,
title: tOnBoardingTitle2,
subTitle: tOnBoardingSubTitle2,
counterText: tOnBoardingCounter2,
bgColor: tOnBoardingPage2Color,
),
),
OnboaringScreenWidget(
model: OnBoardingModel(
image: tOnBoardingImage3,
title: tOnBoardingTitle3,
subTitle: tOnBoardingSubTitle3,
counterText: tOnBoardingCounter3,
bgColor: tOnBoardingPage3Color,
),
),
];
animateToNextSlide() {
int nextPage = controller.currentPage + 1;
controller.animateToPage(page: nextPage);
}
void onPageChangeCallback(int activePageIndex) {
currentPage.value = activePageIndex;
}
skip() => controller.jumpToPage(page: 2);
}
welcome_screen.dart
import 'package:flutter/material.dart';
import 'package:login_flutter_app/src/constants/colors.dart';
import 'package:login_flutter_app/src/constants/image_strings.dart';
import 'package:login_flutter_app/src/constants/sizes.dart';
import 'package:login_flutter_app/src/constants/text_strings.dart';
class WelcomeScreen extends StatelessWidget {
const WelcomeScreen({super.key});
@override
Widget build(BuildContext context) {
var mdeiaQuery = MediaQuery.of(context);
var brightness = mdeiaQuery.platformBrightness;
var height = mdeiaQuery.size.height;
final isDarkMode = brightness == Brightness.dark;
return Scaffold(
backgroundColor: isDarkMode ? tSecondaryColor : tPrimaryColor,
body: Container(
padding: const EdgeInsets.all(tDefaultSize),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image(image: AssetImage(tWelcomeScreenImage), height: height * 0.6),
Column(
children: [
Text(
tWelcomeTitle,
style: Theme.of(context).textTheme.headlineMedium,
),
Text(
tWelcomeSubTitle,
style: Theme.of(context).textTheme.headlineSmall,
textAlign: TextAlign.center,
),
],
),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {},
child: Text(
tLogin.toUpperCase(),
),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: ElevatedButton(
onPressed: () {},
child: Text(
tSignup.toUpperCase(),
),
),
),
],
),
],
),
),
);
}
}
outlined_button_theme.dart
import 'package:flutter/material.dart';
import '../../../constants/colors.dart';
import '../../../constants/sizes.dart';
class TOutlinedButtonTheme {
TOutlinedButtonTheme._(); //To avoid creating instances
/* -- Light Elevated Button Theme -- */
static final lightElevatedButtonTheme = OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
shape: const RoundedRectangleBorder(),
foregroundColor: tSecondaryColor,
side: const BorderSide(color: tSecondaryColor),
padding: const EdgeInsets.symmetric(vertical: tButtonHeight)),
);
/* -- Dark Elevated Button Theme -- */
static final darkElevatedButtonTheme = OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
shape: const RoundedRectangleBorder(),
foregroundColor: tWhiteColor,
side: const BorderSide(color: tWhiteColor),
padding: const EdgeInsets.symmetric(vertical: tButtonHeight)),
);
}
elevated_button_theme.dart
import 'package:flutter/material.dart';
import '../../../constants/colors.dart';
import '../../../constants/sizes.dart';
class TElevatedButtonTheme {
TElevatedButtonTheme._(); //To avoid creating instances
/* -- Light Elevated Button Theme -- */
static final lightElevatedButtonTheme = ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: const RoundedRectangleBorder(),
foregroundColor: tWhiteColor,
backgroundColor: tSecondaryColor,
side: const BorderSide(color: tSecondaryColor),
padding: const EdgeInsets.symmetric(vertical: tButtonHeight),
),
);
/* -- Dark Elevated Button Theme -- */
static final darkElevatedButtonTheme = ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: const RoundedRectangleBorder(),
foregroundColor: tSecondaryColor,
backgroundColor: tWhiteColor,
side: const BorderSide(color: tSecondaryColor),
padding: const EdgeInsets.symmetric(vertical: tButtonHeight),
),
);
}
theme.dart
class TAppTheme {
TAppTheme._();
static ThemeData lightTheme = ThemeData(
brightness: Brightness.light,
textTheme: TTextTheme.lightTextTheme,
outlinedButtonTheme: TOutlinedButtonTheme.lightElevatedButtonTheme,
elevatedButtonTheme: TElevatedButtonTheme.lightElevatedButtonTheme,
);
static ThemeData darkTheme = ThemeData(
textTheme: TTextTheme.darkTextTheme,
outlinedButtonTheme: TOutlinedButtonTheme.darkElevatedButtonTheme,
elevatedButtonTheme: TElevatedButtonTheme.darkElevatedButtonTheme,
);
}
Simulator.Screen.Recording.-.iOS14.-.2023-05-27.at.18.17.20.mp4
fade_in_animation_model.dart
class TAnimatePositon{
final double? topBefore, bottomBefore, leftBefore, rightBefore;
final double? topAfter, bottomAfter, leftAfter, rightAfter;
TAnimatePositon({
this.topBefore,
this.bottomBefore,
this.leftBefore,
this.rightBefore,
this.topAfter,
this.bottomAfter,
this.leftAfter,
this.rightAfter,
});
}
animation_design.dart
class TFadeInAnimation extends StatelessWidget {
TFadeInAnimation({
super.key,
required this.durationInMs,
required this.child,
this.animate,
});
final controller = Get.put(FadeInAnimationController());
final int durationInMs;
final TAnimatePositon? animate;
final Widget child;
@override
Widget build(BuildContext context) {
return Obx(
() => AnimatedPositioned(
duration: Duration(milliseconds: durationInMs),
top: controller.animate.value ? animate!.topAfter : animate!.topBefore,
left:
controller.animate.value ? animate!.leftAfter : animate!.leftAfter,
bottom: controller.animate.value
? animate!.bottomAfter
: animate!.bottomBefore,
right: controller.animate.value
? animate!.rightAfter
: animate!.rightBefore,
child: AnimatedOpacity(
duration: Duration(milliseconds: durationInMs),
opacity: controller.animate.value ? 1 : 0,
child: child,
),
),
);
}
}
fade_in_animation_controller.dart
class FadeInAnimationController extends GetxController {
static FadeInAnimationController get find => Get.find();
RxBool animate = false.obs;
Future startSplashAnimation() async {
await Future.delayed(const Duration(milliseconds: 500));
animate.value = true;
await Future.delayed(const Duration(milliseconds: 3000));
animate.value = false;
await Future.delayed(const Duration(milliseconds: 2000));
Get.offAll(const WelcomeScreen());
}
Future startAnimation() async {
await Future.delayed(const Duration(milliseconds: 500));
animate.value = true;
}
}
splash_screen.dart
Widget build(BuildContext context) {
final controller = Get.put(FadeInAnimationController());
controller.startSplashAnimation();
return Scaffold(
body: Stack(
children: [
TFadeInAnimation(
durationInMs: 1600,
animate: TAnimatePositon(
topAfter: 0,
topBefore: -30,
leftAfter: -30,
leftBefore: 0,
),
child: const Image(
image: AssetImage(
tSplashTopIcon,
),
),
),
welcome_screen.dart
class WelcomeScreen extends StatelessWidget {
const WelcomeScreen({super.key});
@override
Widget build(BuildContext context) {
final controller = Get.put(FadeInAnimationController());
controller.startAnimation();
var mdeiaQuery = MediaQuery.of(context);
var brightness = mdeiaQuery.platformBrightness;
var height = mdeiaQuery.size.height;
final isDarkMode = brightness == Brightness.dark;
return Scaffold(
backgroundColor: isDarkMode ? tSecondaryColor : tPrimaryColor,
body: Stack(
children: [
TFadeInAnimation(
durationInMs: 1200,
animate: TAnimatePositon(
bottomAfter: 0,
bottomBefore: -100,
leftBefore: 0,
leftAfter: 0,
topAfter: 0,
topBefore: 0,
rightAfter: 0,
rightBefore: 0,
),
child: Container(