Creating a Base Screen in Flutter using an abstract class and mixin.
STORY: Each application has its own base UI that remains the same within the app. For example an App bar, background color, or background image of the screen, etc. As a beginner, I used to add the same bunch of code of an App bar to each screen that is not a good practice. It is a best practice if we create a base screen for this. So, let's get started…
- Create an abstract class that extends a stateful widget.
Add a new dart file base_screen.dart.
abstract class BasePageScreen extends StatefulWidget {
BasePageScreen({Key key}) : super(key: key);
}
2. Create an abstract class that extends a state.
abstract class BasePageScreenState<Page extends BasePageScreen> extends State<Page> {
bool _isBack = true;
bool _isCart = true;
String appBarTitle();
void onClickBackButton();
void onClickCart();
void isBackButton(bool isBack) {
_isBack = isBack;
}
void isCartButton(bool isCart) {
_isCart = isCart;
}
}
here, in the example, I am creating 2 screens one is the Home screen and the other is the Cart screen. As the home screen is the first screen back button should be hidden and if the cart screen is already open then the cart button should be hidden so we have added two bools to handle this and added the functions that handle the click events and set the title of the app bar.
3. Create a mixin on BasePageScreenState for our base UI
mixin BaseScreen<Page extends BasePageScreen> on BasePageScreenState<Page> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue.shade200, Colors.pink.shade300]
)
),
),
title: Text(
appBarTitle(),
style: TextStyle(
color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold),
),
leading: _isBack ? IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: Colors.black,
),
onPressed: () {
onClickBackButton();
},
) : Container(),
actions: [
_isCart ? IconButton(
icon: Icon(
Icons.shopping_cart,
color: Colors.black,
),
onPressed: () {
onClickCart();
},
) : Container()
],
),
body: Container(
child: body(),
color: Colors.white,
));
}
Widget body();
}
4. Create a Home screen and state
Add a new dart file home_screen.dart.
class HomeScreen extends BasePageScreen {
@override
_HomeScreenState createState() => _HomeScreenState();
}class _HomeScreenState extends BasePageScreenState<HomeScreen> with BaseScreen {
bool isButtonTapped = false;
@override
void initState() {
isBackButton(false);
super.initState();
}
// TO GIVE THE TITLE OF THE APP BAR
@override
String appBarTitle() {
return "Home";
}
@override
void isBackButton(bool isBack) {
super.isBackButton(isBack);
}
// THIS IS BACK BUTTON CLICK HANDLER
@override
void onClickBackButton() {
print("BACK BUTTON CLICKED FROM HOME");
Navigator.of(context).pop();
}
// THIS IS RIGHT BAR BUTTON CLICK HANDLER
@override
void onClickCart() {
print("CART BUTTON CLICKED");
Navigator.of(context).push(MaterialPageRoute(builder: (context)=> CartScreen()));
}
// THIS WILL RETURN THE BODY OF THE SCREEN
@override
Widget body() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("HOME SCREEN BODY"),
RaisedButton(
onPressed: () {
if(!isButtonTapped) {
setState(() {
isButtonTapped = true;
});
}
},
child: Text(isButtonTapped ? "BUTTON TAPPED" : "BUTTON NOT TAPPED"),
)
],
),
);
}
}
The home screen extends the base stateful widget instead of the stateful widget and _HomeScreenState extends the BasePageScreenState instead of the State. To use the base build method we have added with BaseScreen while creating a state for our home screen.
As we add the BasePageScreenState we’ll get an error in _HomeScreenState to create missing methods so we have added the missing overrides to return the app bar title, handle the back button, and the cart button. To hide the back button on the home screen, override the isBackButton.
5. Add the Cart screen
Add a new dart file cart_screen.dart.
class CartScreen extends BasePageScreen {
@override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends BasePageScreenState<CartScreen> with BaseScreen {
@override
void initState() {
isCartButton(false);
super.initState();
}
@override
void isCartButton(bool isCart) {
super.isCartButton(isCart);
}
@override
String appBarTitle() {
return "Cart";
}
@override
Widget body() {
return Center(
child: Text("CART SCREEN BODY"),
);
}
@override
void onClickBackButton() {
print("BACK BUTTON CLICKED FROM CART");
Navigator.of(context).pop();
}
@override
void onClickCart() {
print("CART BUTTON CLICKED");
}
}
Follow the same steps as the home screen to add the cart screen and override the isCartButton to hide the cart button on the app bar.
6. Update the entry point of the app in the main.dart file and run.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
Happy coding!!