我无法在 Body()
上为 CustomDrawer()
小部件设置动画,两者都在 Stack()
中。我想要做的是在 Body()
上为我的 CustomDrawer()
小部件制作动画(就像 Discord
聊天页面一样)我已经实现了从左到右的滑动,但是我遇到了问题从右到左动画。正如您在下面的 gif 中看到的那样。
我使用 Transform()
和 GestureDetector()
将我的 Body()
小部件从左到右转换。
但是当我想从右向左滑动时出现问题。
我想要的:我希望当用户从左向右滑动时会显示 Drawer1,当用户从右向左滑动时会显示 Drawer2。 Drawer 1 和 2 只不过是一个在 Column()
内有 2 Row()
的单个小部件。
我正在使用 DragStartDetails
检测基于 startDetails.globalPosition.dx
的滑动,这会给我 x 轴的位置。
问题:但是当我尝试更改从右向左滑动的逻辑时,它在 GIF 中给了我这种笨拙的效果。
这是我的 AppDrawer()
小部件,其中发生了所有事情。
class AppDrawer extends StatefulWidget {
final Widget child;
AppDrawer({
key,
required this.child,
}) : super(key: key);
static _AppDrawerState? of(BuildContext context) =>
context.findAncestorStateOfType<_AppDrawerState>();
@override
_AppDrawerState createState() => _AppDrawerState();
}
class _AppDrawerState extends State<AppDrawer>
with SingleTickerProviderStateMixin {
static Duration duration = const Duration(milliseconds: 300);
late AnimationController _controller;
static double maxSlide = 255;
static const dragRightStartVal = 260;
static var dragLeftStartVal = maxSlide - 20;
static bool shouldDrag = false;
bool isDraggingFromRight = false;
bool isDraggingFromLeft = false;
@override
void initState() {
_controller =
AnimationController(vsync: this, duration: _AppDrawerState.duration);
super.initState();
}
void close() => _controller.reverse();
void open() => _controller.forward();
void toggle() {
if (_controller.isCompleted) {
close();
} else {
open();
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _onDragStart(DragStartDetails startDetails) {
// print("dragstart");
// print("startdetails $startDetails");
isDraggingFromLeft = _controller.isDismissed &&
startDetails.globalPosition.dx < dragRightStartVal;
// print("isDraggingFromLeft${isDraggingFromLeft}");
isDraggingFromRight = _controller.isDismissed
? startDetails.globalPosition.dx > -dragLeftStartVal
: _controller.isCompleted &&
startDetails.globalPosition.dx > dragLeftStartVal;
// print("isDraggingFromRight${isDraggingFromRight}");
shouldDrag = isDraggingFromLeft || isDraggingFromRight;
// print("shouldDrag${shouldDrag}");
// print("controller${_controller.isDismissed}${_controller.isCompleted}");
}
void _onDragUpdate(DragUpdateDetails updateDetails) {
if (shouldDrag == false) {
return;
}
double delta = updateDetails.primaryDelta! / maxSlide;
_controller.value += delta;
}
void _onDragEnd(DragEndDetails dragEndDetails) {
if (_controller.isDismissed || _controller.isCompleted) {
return;
}
double _kMinFlingVelocity = 365.0;
double dragVelocity = dragEndDetails.velocity.pixelsPerSecond.dx.abs();
if (dragVelocity >= _kMinFlingVelocity) {
double visualVelocityInPx = dragEndDetails.velocity.pixelsPerSecond.dx /
MediaQuery.of(context).size.width;
_controller.fling(velocity: visualVelocityInPx);
} else if (_controller.value < 0.5) {
close();
} else {
open();
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onHorizontalDragStart: _onDragStart,
onHorizontalDragUpdate: _onDragUpdate,
onHorizontalDragEnd: _onDragEnd,
child: AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, _) {
double animationVal = isDraggingFromRight && _controller.isCompleted
? -_controller.value
: _controller.value;
double translateVal =
animationVal * MediaQuery.of(context).size.width * 0.5;
return Stack(
children: <Widget>[
CustomDrawer(),
Transform(
alignment: Alignment.centerLeft,
transform: Matrix4.identity()..translate(translateVal),
child: GestureDetector(
onTap: () {
if (_controller.isCompleted) {
close();
}
},
child: widget.child,
),
),
],
);
},
),
);
}
}
class CustomDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Material(
color: Colors.black38,
child: SafeArea(
child: Theme(
data: ThemeData(
brightness: Brightness.dark,
),
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: <Widget>[
Container(
padding: const EdgeInsets.all(16),
child: const Text('Drawer 1',
style: TextStyle(fontSize: 30, color: Colors.white)),
),
Container(
width: MediaQuery.of(context).size.width * 0.5,
child: const ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
),
),
Container(
width: MediaQuery.of(context).size.width * 0.5,
child: const ListTile(
leading: Icon(Icons.home),
title: Text('Favourite'),
),
),
Container(
width: MediaQuery.of(context).size.width * 0.5,
child: const ListTile(
leading: Icon(Icons.home),
title: Text('Store'),
),
),
],
),
Column(
children: <Widget>[
Container(
padding: const EdgeInsets.all(16),
child: const Text('Drawer 2',
style: TextStyle(fontSize: 30, color: Colors.white)),
),
Container(
width: MediaQuery.of(context).size.width * 0.5,
child: const ListTile(
leading: Icon(Icons.home),
title: Text('Settings'),
),
),
Container(
width: MediaQuery.of(context).size.width * 0.5,
child: const ListTile(
leading: Icon(Icons.home),
title: Text('Socials'),
),
),
Container(
width: MediaQuery.of(context).size.width * 0.5,
child: const ListTile(
leading: Icon(Icons.home),
title: Text('Feedback'),
),
),
],
),
],
),
),
),
),
);
}
}
任何人都可以帮忙或提供相同的提示吗?谢谢!