Skip to content

Instantly share code, notes, and snippets.

@mkiisoft
Forked from Schwusch/tiltable_stack.dart
Created August 5, 2019 15:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkiisoft/25d987d97a9ac25c46175af316dc06ce to your computer and use it in GitHub Desktop.
Save mkiisoft/25d987d97a9ac25c46175af316dc06ce to your computer and use it in GitHub Desktop.
A tiltable stack, an idea originated from 2dimensions
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class TiltableStack extends StatefulWidget {
final List<Widget> children;
final Alignment alignment;
const TiltableStack({
Key key,
this.children,
this.alignment = Alignment.center,
}) : super(key: key);
@override
_TiltableStackState createState() => _TiltableStackState();
}
class _TiltableStackState extends State<TiltableStack>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> tilt;
Animation<double> depth;
double pitch = 0;
double yaw = 0;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 500), vsync: this)
..addListener(() {
setState(() {
if (tilt != null) {
pitch *= tilt.value;
yaw *= tilt.value;
}
});
})
..forward(from: 1.0);
}
@override
dispose() {
super.dispose();
_controller.dispose();
}
cancelPan() {
tilt = Tween<double>(
begin: 1.0,
end: 0.0,
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.elasticIn.flipped,
),
);
depth = tilt;
_controller.forward();
}
startPan() {
tilt = null;
depth = Tween<double>(
begin: 1.0,
end: 0.0,
).animate(
CurvedAnimation(
parent: _controller,
curve: const Cubic(1.0, 0.0, 1.0, 1.0),
),
);
_controller.reverse();
}
updatePan(DragUpdateDetails drag) {
setState(() {
var size = MediaQuery.of(context).size;
pitch += drag.delta.dy * (1 / size.height);
yaw -= drag.delta.dx * (1 / size.width);
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onPanUpdate: updatePan,
onPanEnd: (_) => cancelPan(),
onPanCancel: cancelPan,
onPanDown: (_) => startPan(),
child: Stack(
alignment: widget.alignment,
children: widget.children
.asMap()
.map(
(i, element) {
return MapEntry(
i,
Stack(
alignment: Alignment.center,
children: [
Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(pitch)
..rotateY(yaw)
..translate(-yaw * i * 70, pitch * i * 70, 0)
..scale((depth?.value ?? 0) * (i + 1) * 0.1 + 1),
child: element,
alignment: FractionalOffset.center,
),
],
),
);
},
)
.values
.toList(),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment