In this article, we will learn the Flutter UI of splash, login, signup, and forget password screen. We will design these screens by using the GetX State Management. You will learn what is GetX and how you can use this in your projects. You will learn how to navigate to other screens by using GetX, the best folder structure for app development, Flutter custom button widget, Flutter custom text field widget, SingleChildScrollView widget, vertical scrolling, and more.
What is GetX?
GetX is a micro-framework that aims to provide a top-notch development experience by minimizing the boilerplate combined with neat syntax and a simple approach. When developing with GetX, everything feels self-evident and practical. It’s a solid blend of simplicity and power. It’s one of those rare packages that try to do everything and actually do it.
GetX provides a combination of State Management, Dependency Injection, and Route Management solutions that work great together. But things don’t end here, it provides a ton of utilities that make it easy to implement internationalization, theming, validation, etc.
All of these solutions and utilities are packed in individually compiled containers which give us the freedom to choose what to use and what not to, without compromising performance. However, once you’re using GetX, it’s hard to not use everything this package has to offer because everything works so seamlessly together. And, that’s what I call The GetX Ecosystem.
Let’s Start the Coding
► Flutter UI Design
► Splash Screen Flutter UI
► Login Screen Flutter UI
► Signup Screen Flutter UI
► Forget Password Screen Flutter UI
Folder Structure
In the constants Folder, I place all the colors and images by declaring their classes. You can see the code at the bottom for app_colors.dart file and also app_icons.dart file.
app_colors.dart file
import 'package:flutter/material.dart';
class AppColors {
static const Color mainColor = Color(0xff2031C9);
static const Color primaryColor = Color(0xff1f08ab);
static const Color whiteColor = Color(0xffFFFFFF);
static const Color blackColor = Color(0xff000000);
static const Color greyColor = Color(0xff7a7a7a);
}
app_icons.dart file
class AppIcons {
static const String appLogo = 'assets/images/Asset 2 1.png';
static const String userIcon = 'assets/icons/icons8_user_96px_2 1 (2).png';
static const String emailIcon = 'assets/icons/icons8_user_96px_2 1.png';
static const String lockIcon = 'assets/icons/icons8_user_96px_2 1 (1).png';
static const String eyeIcon = 'assets/icons/i';
static const String googleIcon = 'assets/icons/icons8_Facebook_96px 1.png';
static const String fbIcon = 'assets/icons/icons8_Facebook_96px 1 (1).png';
}
Here are some custom widgets in the widgets folder in which I make a custom_button widget and also make a custom_textfield widget.
custom_button.dart file
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import '../constants/app_colors.dart';
class CustomButton extends StatelessWidget {
final String? btnText;
final VoidCallback? onTap;
final Color? btnColor;
final Color? onPrimaryColor;
final Widget? btnDataRow;
const CustomButton({Key? key,
required this.onTap,
required this.btnText,
this.btnColor = AppColors.primaryColor,
this.btnDataRow,
this.onPrimaryColor = AppColors.blackColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: ElevatedButton(
onPressed: onTap,
style: ElevatedButton.styleFrom(
primary: btnColor,
onPrimary: onPrimaryColor,
minimumSize: Size(width, height * 0.08),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
child: btnDataRow ?? Center(
child: Text(btnText!,
style: GoogleFonts.poppins(
color: AppColors.whiteColor,
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
),
);
}
}
custom_field.dart file
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import '../constants/app_colors.dart';
class CustomTextField extends StatelessWidget {
final TextEditingController controller;
final TextInputType keyboardType;
final String hintText;
final bool obscureText;
final String prefixIconPath;
final Widget? suffixIcon;
const CustomTextField({Key? key,
required this.controller,
required this.obscureText,
required this.hintText,
required this.keyboardType,
required this.prefixIconPath,
this.suffixIcon,
}) : super(key: key);
@override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Container(
height: 50.0,
width: width,
margin: const EdgeInsets.symmetric(horizontal: 20.0),
decoration: BoxDecoration(
color: AppColors.whiteColor,
borderRadius: BorderRadius.circular(10.0),
),
child: TextFormField(
style: GoogleFonts.poppins(
fontSize: 14.0,
fontWeight: FontWeight.w400,
),
obscureText: obscureText,
cursorColor: AppColors.mainColor,
controller: controller,
keyboardType: keyboardType,
decoration: InputDecoration(
border: InputBorder.none,
prefixIcon: Image.asset(prefixIconPath),
suffixIcon: suffixIcon ?? const SizedBox(),
hintText: hintText,
hintStyle: GoogleFonts.poppins(
fontSize: 14.0,
fontWeight: FontWeight.w400,
),
contentPadding: const EdgeInsets.only(top: 16.0),
),
),
);
}
}
Splash Screen Flutter UI
class SplashScreen extends GetView<SplashController> {
const SplashScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
Get.put(SplashController());
return Scaffold(
backgroundColor: AppColors.mainColor,
body: Center(
child: Image.asset(AppIcons.appLogo),
),
);
}
}
Splash Screen GetX Controller
class SplashController extends GetxController {
@override
void onInit() {
super.onInit();
Timer(
const Duration(seconds: 3),
() => Get.off(
LoginScreen(),
),
);
}
}
Login Screen Flutter UI
class LoginScreen extends GetView<LoginController> {
const LoginScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
Get.put(LoginController());
return Scaffold(
backgroundColor: AppColors.mainColor,
body: SafeArea(
child: SizedBox(
height: height,
width: width,
child: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 30.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
/// app icon
SizedBox(height: height * 0.05),
Image.asset(
AppIcons.appLogo,
height: 70,
),
/// Don't Have an Account text
SizedBox(height: height * 0.05),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Don\'t have an account?',
style: GoogleFonts.poppins(
fontSize: 12.0,
fontWeight: FontWeight.w500,
color: AppColors.whiteColor,
),
),
const WidgetSpan(child: SizedBox(width: 10.0)),
TextSpan(
text: 'SIGN UP',
style: GoogleFonts.poppins(
fontSize: 12.0,
fontWeight: FontWeight.w500,
color: AppColors.whiteColor,
),
recognizer: TapGestureRecognizer()
..onTap = () => Get.to(
const SignupScreen(),
),
),
],
),
),
/// email field
SizedBox(height: height * 0.06),
CustomTextField(
controller: controller.emailController,
obscureText: false,
hintText: 'Email',
keyboardType: TextInputType.emailAddress,
prefixIconPath: AppIcons.emailIcon,
suffixIcon: null,
),
/// password field
SizedBox(height: height * 0.02),
CustomTextField(
controller: controller.passwordController,
obscureText: true,
hintText: 'Password',
keyboardType: TextInputType.text,
prefixIconPath: AppIcons.lockIcon,
suffixIcon: null,
),
/// Login button
SizedBox(height: height * 0.05),
CustomButton(
onTap: () {},
btnText: 'Login',
),
/// forgot password Button
SizedBox(height: height * 0.01),
TextButton(
onPressed: () {
Get.to(ForgotPasswordScreen());
},
child: Text(
'Forgot Password?',
style: GoogleFonts.poppins(
fontSize: 14.0,
fontWeight: FontWeight.w400,
color: AppColors.whiteColor,
),
),
),
/// login with Google button
SizedBox(height: height * 0.08),
CustomButton(
onTap: () {},
btnText: '',
btnColor: AppColors.whiteColor,
btnDataRow: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(AppIcons.googleIcon),
const SizedBox(width: 8.0),
Text(
'Login with Google',
style: GoogleFonts.poppins(
fontSize: 14.0,
fontWeight: FontWeight.w400,
color: AppColors.blackColor,
),
),
],
),
),
/// login with facebook
SizedBox(height: height * 0.02),
CustomButton(
onTap: () {},
btnText: '',
btnColor: AppColors.whiteColor,
btnDataRow: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(AppIcons.fbIcon),
const SizedBox(width: 8.0),
Text(
'Login with Facebook',
style: GoogleFonts.poppins(
fontSize: 14.0,
fontWeight: FontWeight.w400,
color: AppColors.blackColor,
),
),
],
),
),
],
),
),
),
),
);
}
}
Login Screen GetX Controller
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class LoginController extends GetxController {
TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController();
}
Signup Screen Flutter UI
class SignupScreen extends GetView<SignupController> {
const SignupScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
Get.put(SignupController());
return Scaffold(
backgroundColor: AppColors.mainColor,
body: SafeArea(
child: SizedBox(
height: height,
width: width,
child: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 30.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
/// app icon
SizedBox(height: height * 0.05),
Image.asset(
AppIcons.appLogo,
height: 70,
),
/// Don't Have an Account text
SizedBox(height: height * 0.05),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Already have account?',
style: GoogleFonts.poppins(
fontSize: 12.0,
fontWeight: FontWeight.w500,
color: AppColors.whiteColor,
),
),
const WidgetSpan(child: SizedBox(width: 10.0)),
TextSpan(
text: 'SIGN IN',
style: GoogleFonts.poppins(
fontSize: 12.0,
fontWeight: FontWeight.w500,
color: AppColors.whiteColor,
),
recognizer: TapGestureRecognizer()
..onTap = () => Get.to(
const LoginScreen(),
),
),
],
),
),
/// full name field
SizedBox(height: height * 0.06),
CustomTextField(
controller: controller.nameController,
obscureText: false,
hintText: 'Full Name',
keyboardType: TextInputType.name,
prefixIconPath: AppIcons.userIcon,
suffixIcon: null,
),
/// email field
SizedBox(height: height * 0.02),
CustomTextField(
controller: controller.emailController,
obscureText: false,
hintText: 'Email',
keyboardType: TextInputType.emailAddress,
prefixIconPath: AppIcons.emailIcon,
suffixIcon: null,
),
/// password field
SizedBox(height: height * 0.02),
CustomTextField(
controller: controller.passwordController,
obscureText: true,
hintText: 'Password',
keyboardType: TextInputType.text,
prefixIconPath: AppIcons.lockIcon,
suffixIcon: null,
),
/// signup button
SizedBox(height: height * 0.05),
CustomButton(
onTap: () {},
btnText: 'Sign Up',
),
/// Terms of services
SizedBox(height: height * 0.03),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'By Signing Up, You agree our ',
style: GoogleFonts.poppins(
fontSize: 12.0,
fontWeight: FontWeight.w500,
color: AppColors.whiteColor,
),
),
TextSpan(
text: 'TERMS OF SERVICES',
style: GoogleFonts.poppins(
fontSize: 12.0,
fontWeight: FontWeight.w500,
color: AppColors.whiteColor,
decoration: TextDecoration.underline,
),
///recognizer: TapGestureRecognizer(),
),
],
),
),
/// login with Google button
SizedBox(height: height * 0.04),
CustomButton(
onTap: () {},
btnText: '',
btnColor: AppColors.whiteColor,
btnDataRow: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(AppIcons.googleIcon),
const SizedBox(width: 8.0),
Text(
'Login with Google',
style: GoogleFonts.poppins(
fontSize: 14.0,
fontWeight: FontWeight.w400,
color: AppColors.blackColor,
),
),
],
),
),
/// login with facebook
SizedBox(height: height * 0.02),
CustomButton(
onTap: () {},
btnText: '',
btnColor: AppColors.whiteColor,
btnDataRow: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(AppIcons.fbIcon),
const SizedBox(width: 8.0),
Text(
'Login with Facebook',
style: GoogleFonts.poppins(
fontSize: 14.0,
fontWeight: FontWeight.w400,
color: AppColors.blackColor,
),
),
],
),
),
],
),
),
),
),
);
}
}
Signup Screen GetX Controller
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class SignupController extends GetxController {
TextEditingController nameController = TextEditingController();
TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController();
}
Forget Password Screen Flutter UI
class ForgotPasswordScreen extends GetView<ForgotPassController> {
const ForgotPasswordScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
Get.put(ForgotPassController());
return Scaffold(
backgroundColor: AppColors.mainColor,
body: SafeArea(
child: SizedBox(
height: height,
width: width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
/// app icon
SizedBox(height: height * 0.05),
Image.asset(AppIcons.appLogo,
height: 70,
),
/// Don't Have an Account text
SizedBox(height: height * 0.05),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Forget Password',
style: GoogleFonts.poppins(
fontSize: 12.0,
fontWeight: FontWeight.w500,
color: AppColors.whiteColor,
),
),
],
),
),
/// email field
SizedBox(height: height * 0.06),
CustomTextField(
controller: controller.emailController,
obscureText: false,
hintText: 'Email',
keyboardType: TextInputType.emailAddress,
prefixIconPath: AppIcons.emailIcon,
suffixIcon: null,
),
],
),
),
),
);
}
}
Forget Password GetX Controller
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class ForgotPassController extends GetxController {
TextEditingController emailController = TextEditingController();
}
► Source code: https://github.com/flutter99/flutter-ui-speed-code
1 Response
[…] Flutter UI, Splash Login Signup Forgot Password Screen […]