But enough introduction! It’s CODING TIME 🤓💻

-First thing first… where to start? Why there’s no guides?! What I need to change?! WHY?! WHY?!!!

-Relax, I said!!!

average drama in Latin America telenovelas

There’s one thing we know… when click pan or hover with our mouse, we need to update several values, the first ones in mind are “rotation X and Y” and Flutter always has a Widget ready for that:

Transform 🥰

This baby boy has sooooooooo (x100) many methods available to modify Widgets, like, so many! You want to scale, skew, translate, rotate, etc you name it, it has it all.

One thing you’d notice while using “Transform” is the class Matrix4, and no, Neo has nothing to do with this…

and not even the incredible coincidence of Matrix 4 coming in 2021 👀

Matrix4 is nothing more than a vector 4D with x, y , z, scale factor and several other goodies. You can even read more about it over here:

For our cool demo, we’re going to use “rotateX”, “rotateY”, “setEntry” (this one is super interesting as it will create our 3D effect) and “translate”.

Ok, first thing first, we need to do some measures:

final size = MediaQuery.of(context).size;

that way we can check out width and height between several calculation needed for this trick.

We need as well some variables to achieve the rotate + parallax effect:

double localX = 0;

double localY = 0;

bool defaultPosition = true;

those will be super helpful while panning and hovering our Widget. We also need the percentage of where your mouse/finger is related to our Widget:

double percentageX = (localX / (size.width - 40)) * 100;

double percentageY = (localY / 230) * 100;

I this case, my Widget has a size of “size.width — 40” for its width and “230” for the height.

If we opt to pan our Widget, we need to use the good old GestureDetector:

GestureDetector(

onPanCancel: () => setState(() => defaultPosition = true),

onPanDown: (_) => setState(() => defaultPosition = false),

onPanEnd: (_) => setState(() {

localY = 115;

localX = (size.width - 40) / 2;

defaultPosition = true;

}),

onPanUpdate: (details) {

if (mounted) setState(() => defaultPosition = false);

if (details.localPosition.dx > 0 &&

details.localPosition.dy < 230) {

if (details.localPosition.dx < size.width - 40 &&

details.localPosition.dy > 0) {

localX = details.localPosition.dx;

localY = details.localPosition.dy;

}

}

}

and if you take a closer look, you’d notice that I’m taking half of width and height to return the view to its default position, while onPanUpdate gets all the local position for that Widget between the ranges of itself.

One we get that, we’ll apply our Transformation, and the following code achieves that goal:

Transform(

transform: Matrix4.identity()

..setEntry(3, 2, 0.001)

..rotateX(defaultPosition ? 0 : (0.3 * (percentageY / 50) + -0.3))

..rotateY(defaultPosition ? 0 : (-0.3 * (percentageX / 50) + 0.3)),

alignment: FractionalOffset.center,

child: Container(), // back layer

)

like I said before, setEntry(3, 2, 0.001) plays a huge role here as this one will create the desire 3D effect for the back layer and our rotation will look soft and smooth. Oh, very important, we need a center pivot for this to happen, if not, position 0,0 will be the selected one:

alignment: FractionalOffset.center fixes the “issue”.

What, we need to create our parallax effect for the front layer, this one will move “more” as it should be “closer” to us… like the road trip I talked before.

Moving our X and Y positions, just a little bit, will add some extra movement from our back layer.

Remember, this from layer should be inside a Stack Widget to have freedom of movement and be on top (Z position):

Matrix4.identity()

..translate(

defaultPosition

? 0.0

: (15 * (percentageX / 50) + -15),

defaultPosition

? 0.0

: (15 * (percentageY / 50) + -15),

0.0),

alignment: FractionalOffset.center,

child: Container(), // front layer

}

Pufffff… 😓 after all this math work we need to relax a bit, but enjoy the cool thing we just created!

SFXP Meetup — 2 Layers Parallax

But this Medium post was about using a mouse… not a finger, what about Hovering?

Cool thing about hover effect is that you don’t even need to touch the Widget, you need to move your mouse cursor on top of it and get some information about it:

MouseRegion 🐁 🖱

This cool Widget allows us to know when our mouse cursor: Enter, Exit and Hover our Widget.

MouseRegion(

onEnter: (_) => setState(() => defaultPosition = false),

onExit: (_) => setState(() {

localY = (size.height) / 2;

localX = (size.width * 0.45) / 2;

defaultPosition = true;

}),

onHover: (details) {

if (mounted) setState(() => defaultPosition = false);

if (details.localPosition.dx > 0 && details.localPosition.dy > 0) {

if (details.localPosition.dx < (size.width * 0.45) * 1.5 && details.localPosition.dy > 0) {

localX = details.localPosition.dx;

localY = details.localPosition.dy;

}

}

},

Our logic it’s pretty much the same as GestureDetector but we have one less method to be called.

Following our logic from before:

Transform(

transform: Matrix4.identity()

..setEntry(3, 2, 0.001)

..rotateX(defaultPosition ? 0 : (1.2 * (percentageY / 50) + -1.2))

..rotateY(defaultPosition ? 0 : (-0.3 * (percentageX / 50) + 0.3)),

alignment: FractionalOffset.center,

child: Container(), // back layer

)

and for our front layer:

Transform(

transform: Matrix4.identity()

..translate(defaultPosition ? 0.0 : (70 * (percentageX / 50) + -70),

defaultPosition ? 0.0 : (80 * (percentageY / 50) + -80), 0.0),

alignment: FractionalOffset.center,

child: Container(), // front layer

What’s the result from all this nerd data?

some fancy cool 2 layers parallax effect on Flutter Web hovering the mouse cursor.

But, you know what’s actually REALLY COOL?! This works on DartPad as well!

Flutter really has the power to run everywhere 💻📱