Neubrutalism UI design pattern with Flutter
This is a small tutorial on creating Neubrutalism interface elements using Flutter
Neubrutalism is a trend focusing on creating structures and layouts that are simple but also impactful, utilizing bold colors, sharp lines, and geometric shapes to create a unique look.
Let’s Get Started
Step 1
Create a Container
Container(
height: MediaQuery.of(context).size.height * 0.1,
width: MediaQuery.of(context).size.width * 0.6,
decoration: BoxDecoration(
color: Colors.yellow.shade300,
),
child: const Center(
child: Text(
"Click",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
Step 2
Decorate the container.
- Border
border: Border.all(color: Colors.black, width: 3),
- Box Shadow
boxShadow: [
BoxShadow(color: Colors.black, offset: Offset(7, 7))
],
- Border Radius
borderRadius: const BorderRadius.only(
topRight: Radius.circular(15),
bottomLeft: Radius.circular(15)),
Step 3
Wrap the container with an animated container and set the duration. You should also wrap the animated container with a gesture detector and set the onTapUp and onTapDown properties.
GestureDetector(
onTapUp: (val) {
},
onTapDown: (val) {
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
child: Container(
height: MediaQuery.of(context).size.height * 0.1,
width: MediaQuery.of(context).size.width * 0.6,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topRight: Radius.circular(15),
bottomLeft: Radius.circular(15)),
color: Colors.yellow.shade300,
boxShadow: [
BoxShadow(color: Colors.black, offset: Offset(7, 7)),
],
border: Border.all(color: Colors.black, width: 3),
),
child: const Center(
child: Text(
"Click",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
Create the boolean variable isTapped with the value false.
bool isTapped = false;
Set isTapped to be false in onTapUp and true in onTapDown.
onTapUp: (val) {
setState(() {
isTapped = false;
});
},
onTapDown: (val) {
setState(() {
isTapped = true;
});
},
set another offset for boxShadow of the container while isTapped is true
boxShadow: [
isTapped == false
? BoxShadow(color: Colors.black, offset: Offset(7, 7))
: BoxShadow(
color: Colors.black, offset: Offset(0.5, 0.5)),
],
Output
Full Code
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isTapped = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Neubrutalism"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
onTapUp: (v) {
setState(() {
isTapped = false;
});
},
onTapDown: (v) {
setState(() {
isTapped = true;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
child: Container(
height: MediaQuery.of(context).size.height * 0.1,
width: MediaQuery.of(context).size.width * 0.6,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topRight: Radius.circular(15),
bottomLeft: Radius.circular(15)),
color: Colors.yellow.shade300,
boxShadow: [
isTapped == false
? BoxShadow(color: Colors.black, offset: Offset(7, 7))
: BoxShadow(
color: Colors.black, offset: Offset(0.5, 0.5)),
],
border: Border.all(color: Colors.black, width: 3),
),
child: const Center(
child: Text(
"Click",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
],
),
),
);
}
}
Thanks : )