Neubrutalism UI design pattern with Flutter

Akhil George
3 min readApr 12, 2023

--

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 : )

--

--