我试图按照此tutorial实现GuillotineMenu,我设法创建了很棒的动画菜单,但是菜单下方的列表视图无法检测到手势(滚动)。如何将滚动手势发送到列表视图?当我在菜单上使用IgnorePointer时,滚动条起作用,但菜单不起作用。我可以在堆栈上的两个小部件上检测手势吗?
P.S在此代码中,我使用了手势检测器而不是listview
代码:
home.dart
import 'package:Pixelitg/GuillotineMenu.dart';
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
@override
_HomeState createState() => new _HomeState();
}
class _HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
return SafeArea(
top: false,
bottom: false,
child: new Container(
child: new Stack(
alignment: Alignment.topLeft,
children: <Widget>[
new Page(),
new GuillotineMenu(),
],
),
),
);
}
}
GuillotineMenu:
import 'package:Pixelitg/news.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class GuillotineMenu extends StatefulWidget {
@override
_GuillotineMenuState createState() => new _GuillotineMenuState();
}
enum _GuillotineAnimationStatus { closed, open, animating }
class _GuillotineMenuState extends State<GuillotineMenu>
with SingleTickerProviderStateMixin {
double pi = 22 / 7;
String _title = "Our Work";
AnimationController animationControllerMenu;
Animation<double> animationMenu;
Animation<double> animationTitleFadeInOut;
_GuillotineAnimationStatus menuAnimationStatus =
_GuillotineAnimationStatus.closed;
double rotationAngle = 0.0;
_handleMenuOpenClose() {
if (menuAnimationStatus == _GuillotineAnimationStatus.closed) {
animationControllerMenu.forward().orCancel;
} else if (menuAnimationStatus == _GuillotineAnimationStatus.open) {
animationControllerMenu.reverse().orCancel;
}
}
@override
void initState() {
super.initState();
///
/// Initialization of the animation controller
///
animationControllerMenu = new AnimationController(
duration: const Duration(milliseconds: 1000), vsync: this)
..addListener(() {
setState(() {});
})
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
///
/// When the animation is at the end, the menu is open
///
menuAnimationStatus = _GuillotineAnimationStatus.open;
} else if (status == AnimationStatus.dismissed) {
///
/// When the animation is at the beginning, the menu is closed
///
menuAnimationStatus = _GuillotineAnimationStatus.closed;
} else {
///
/// Otherwise the animation is running
///
menuAnimationStatus = _GuillotineAnimationStatus.animating;
}
});
animationTitleFadeInOut =
new Tween(begin: 1.0, end: 0.0).animate(new CurvedAnimation(
parent: animationControllerMenu,
curve: new Interval(
0.0,
0.5,
curve: Curves.ease,
),
));
animationMenu =
new Tween(begin: -pi / 2.0, end: 0.0).animate(new CurvedAnimation(
parent: animationControllerMenu,
curve: Curves.bounceOut,
reverseCurve: Curves.bounceIn,
));
///
/// Initialization of the menu appearance animation
///
new Tween(begin: -pi / 2.0, end: 0.0).animate(animationControllerMenu);
}
@override
void dispose() {
animationControllerMenu.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
MediaQueryData mediaQueryData = MediaQuery.of(context);
double screenWidth = mediaQueryData.size.width;
double screenHeight = mediaQueryData.size.height;
return new Material(
color: Colors.transparent,
child: new Transform.rotate(
angle: animationMenu.value,
origin: new Offset(24.0, 56.0),
alignment: Alignment.topLeft,
child: Container(
width: screenWidth,
height: screenHeight,
color: Color(0xFF333333),
child: new Stack(
children: <Widget>[
_buildMenuTitle(),
_buildMenuIcon(),
_buildMenuContent(),
],
),
),
),
);
}
///
/// Menu Title
///
Widget _buildMenuTitle() {
double screenWidth = MediaQuery.of(context).size.width;
return new Positioned(
top: 32.0,
left: 40.0,
width: screenWidth,
height: 24.0,
child: new Transform.rotate(
alignment: Alignment.topLeft,
origin: Offset.zero,
angle: pi / 2.0,
child: new Center(
child: new Container(
width: double.infinity,
height: double.infinity,
child: new Opacity(
opacity: animationTitleFadeInOut.value,
child: new Text(_title,
textAlign: TextAlign.center,
style: new TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold,
letterSpacing: 2.0,
)),
),
),
)),
);
}
///
/// Menu Icon
///
Widget _buildMenuIcon() {
return new Positioned(
top: 32.0,
left: 4.0,
child: new IconButton(
icon: const Icon(
Icons.menu,
color: Colors.white,
),
onPressed: _handleMenuOpenClose,
),
);
}
///
/// Menu content
///
Widget _buildMenuContent() {
final List<Map> _menus = <Map>[
{
"icon": Icons.work,
"title": "Our Work",
},
{
"icon": FontAwesomeIcons.plusSquare,
"title": "Services",
},
{
"icon": Icons.view_agenda,
"title": "News Feed",
},
{
"icon": Icons.person,
"title": "Our Team",
},
{
"icon": FontAwesomeIcons.phoneVolume,
"title": "Contact Us",
},
];
return new Padding(
padding: const EdgeInsets.only(left: 64.0, top: 96.0),
child: new Container(
width: double.infinity,
height: double.infinity,
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: _menus.map((menuItem) {
return new FlatButton(
child: ListTile(
leading: new Icon(
menuItem["icon"],
color:
menuItem["title"] == _title ? Colors.cyan : Colors.white,
),
title: new Text(
menuItem["title"],
style: new TextStyle(
color: menuItem["title"] == _title
? Colors.cyan
: Colors.white,
fontSize: 24.0),
),
),
onPressed: () {
setState(() {
_title = menuItem["title"];
_handleMenuOpenClose();
});
},
);
}).toList(),
),
),
);
}
}
class Page extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
child: Container(
padding: const EdgeInsets.only(top: 90.0),
child: News(),
),
onDoubleTap: (){print('object');},
),
);
}
}