Flutter 中的 3D 运动动画
3D movement animation in Flutter
我正在使用 Transform
在卡片上进行 3D 运动。使用 onPanUpdate
它会一直移动直到完全倾斜。当您触摸靠近边缘的任何点时,我如何限制或控制运动最多进行一半的方式。
这是我应用 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(),
),
),
我使用 物理模拟 概念解决了这个问题。我将 onPanStart 和 onPanEnd 添加到 GestureDetector 并且还定义了一个 controller听变化控制动作流畅
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,
),
),
);
}
}
我正在使用 Transform
在卡片上进行 3D 运动。使用 onPanUpdate
它会一直移动直到完全倾斜。当您触摸靠近边缘的任何点时,我如何限制或控制运动最多进行一半的方式。
这是我应用 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(),
),
),
我使用 物理模拟 概念解决了这个问题。我将 onPanStart 和 onPanEnd 添加到 GestureDetector 并且还定义了一个 controller听变化控制动作流畅
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,
),
),
);
}
}