Issue
I am using Transform
to have a 3D movement on a card. with onPanUpdate
it moves all way until it tilts completely. How can I restrict or control the movement in a way that it goes half way at most when you touch any point close to the edges.
Here is how I applied Transform
:
Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001) // perspective
..rotateX(0.001 * _offset.dy) // changed
..rotateY(-0.001 * _offset.dx), // changed
alignment: FractionalOffset.center,
child: GestureDetector(
onPanUpdate: (details) => setState(() =>
// Offset(-0.1, -0.1) < details.delta ||
// details.delta < Offset(0.1, 0.1)
// ?
_offset += details.delta
// : _offset = _offset
),
child: ReusableCard(),
),
),
Solution
I solved the issue by using physics-simulation concept. I added onPanStart and onPanEnd to the GestureDetector and also defining a controller to listen to changes and control the movement to be smooth
class ReusableCard extends StatefulWidget {
@override
_ReusableCardState createState() => _ReusableCardState();
}
class _ReusableCardState extends State<ReusableCard>
with TickerProviderStateMixin {
AnimationController _offsetController;
Animation<Offset> _offsetAnimation;
Offset _offset = Offset.zero;
static const double limitParallaxOffset = 350;
void _runOffsetAnimation() {
_offsetAnimation = _offsetController.drive(Tween<Offset>(
begin: _offset,
end: Offset.zero,
));
_offsetController.reset();
_offsetController.forward();
}
@override
void initState() {
super.initState();
_offsetController =
AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_offsetController.addListener(() {
setState(() {
_offset = _offsetAnimation.value;
});
});
}
@override
void dispose() {
super.dispose();
_offsetController.dispose();
}
@override
Widget build(BuildContext context) {
return Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001) // perspective
..rotateX(0.001 * _offset.dy) // changed
..rotateY(-0.001 * _offset.dx), // changed
alignment: FractionalOffset.center,
child: GestureDetector(
onPanStart: (details) {
_offsetController.stop();
},
onPanUpdate: (details) {
setState(() {
Offset(-limitParallaxOffset, -limitParallaxOffset) < _offset &&
_offset < Offset(limitParallaxOffset, limitParallaxOffset)
? _offset += details.delta / 2
: _offset = Offset.zero;
});
},
onPanEnd: (details) {
_runOffsetAnimation();
},
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.blue,
offset: Offset(0, 20),
blurRadius: 30.0),
],
),
height: 100,
width: 100,
),
),
);
}
}
Answered By – Zahra
Answer Checked By – Mildred Charles (FlutterFixes Admin)