基本上,我有一个顶部导航栏(菜单),并希望它在鼠标悬停时展开。当
onHover
属性变为 true
时,它应该展开并向下动画,而当 onHover
属性变为 false
时,它应该折叠并向上动画。
但是,当它展开时,它的高度应该受到其子级 + 填充的大小的限制。 我不想为容器设置特定的高度。
仅供参考,这是我的代码:
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool isTopBarHovered = false;
void handleTopBarHover(bool isHovered) {
setState(() {
isTopBarHovered = isHovered;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MediaQuery.of(context).size.width < 800
? AppBar()
: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 48.0),
child: TopNavigationBar(onHover: handleTopBarHover),
),
body: Stack(
children: [
Container(),
Positioned(
top: 0,
left: 0,
right: 0,
child: AnimatedSize(
duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut,
child: isTopBarHovered
? Container(
color: Colors.black,
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 88.0),
child: Center(
child: Text('Additional Widget'),
),
),
)
: const SizedBox(height: 0),
),
),
],
),
);
}
}
class TopNavigationBar extends StatefulWidget {
final Function(bool) onHover;
const TopNavigationBar({super.key, required this.onHover});
@override
State<TopNavigationBar> createState() => _TopNavigationBarState();
}
class _TopNavigationBarState extends State<TopNavigationBar> {
@override
Widget build(BuildContext context) {
bool isHover = false;
return Container(
color: Colors.black,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap:(){},
onHover: (val) {
setState(() {
isHover = val;
});
widget.onHover(isHover);
},
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 8.0),
child: Text(
"Item 01",
style: TextStyle(color: Colors.white),
),
),
),
],
),
);
}
}
这部分有效,我只能在展开时使其具有动画效果,当它折叠时,它就会消失而没有动画。
这是@pskink 答案的解释和演示
之前的代码:
Positioned(
top: 0,
left: 0,
right: 0,
child: AnimatedSize(
duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut,
child: isTopBarHovered
? Container(
color: Colors.black,
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 88.0),
child: Center(
child: Text('Additional Widget'),
),
),
)
: const SizedBox(height: 0),
),
),
步骤:
AnimatedSize
替换为 AnimatedAlign
并将对齐设置为底部,因为您将向下设置小部件的动画,因此必须将其粘贴到底部heightFactor
变化,就像调整布局边界框比例一样,1 或 0之后的代码:
Positioned(
top: 0,
left: 0,
right: 0,
child: AnimatedAlign(
duration: const Duration(milliseconds: 250),
alignment: Alignment.bottomCenter,
heightFactor: isTopBarHovered ? 1 : 0,
curve: Curves.easeInOut,
child: Container(
color: Colors.black,
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 88.0),
child: Center(
child: Text(
'Additional Widget',
style: TextStyle(color: Colors.white),
),
),
),
),
),
),
这是结果:
感谢@pskink
这是最终的代码:
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool isTopBarHovered = false;
void handleTopBarHover(bool isHovered) {
setState(() {
isTopBarHovered = isHovered;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MediaQuery.of(context).size.width < 800
? AppBar()
: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 48.0),
child: TopNavigationBar(onHover: handleTopBarHover),
),
body: Stack(
children: [
Container(),
Positioned(
top: 0,
left: 0,
right: 0,
child: AnimatedAlign(
duration: const Duration(milliseconds: 250),
alignment: Alignment.bottomCenter,
heightFactor: isTopBarHovered ? 1 : 0,
curve: Curves.easeInOut,
child: Container(
color: Colors.black,
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 88.0),
child: Center(
child: Text(
'Additional Widget',
style: TextStyle(color: Colors.white),
),
),
),
),
),
),
],
),
);
}
}
class TopNavigationBar extends StatefulWidget {
final Function(bool) onHover;
const TopNavigationBar({super.key, required this.onHover});
@override
State<TopNavigationBar> createState() => _TopNavigationBarState();
}
class _TopNavigationBarState extends State<TopNavigationBar> {
@override
Widget build(BuildContext context) {
bool isHover = false;
return Container(
color: Colors.black,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {},
onHover: (val) {
setState(() {
isHover = val;
});
widget.onHover(isHover);
},
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 8.0),
child: Text(
"Item 01",
style: TextStyle(color: Colors.white),
),
),
),
],
),
);
}
}