溢出容器顶部的可扩展按钮
Expandable button overflowing top of container
我正在尝试制作一个可扩展按钮,有点像可扩展 fab,只是它不是 fab,因为它不是浮动的。这是透视图的可扩展工厂:
不过,我想要实现的是拥有一个 独立 按钮,该按钮在其上方展开并带有一个菜单。自包含以粗体显示,因为我希望无需修改父结构即可轻松使用小部件。
因此,如果您将下面的代码复制粘贴到 dartpad 中,您会在底部看到一个黄色条。但是,如果您取消注释被注释的行,表示菜单展开,您会看到底部栏被推到顶部。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: [
Expanded(child: Container(color: Colors.purple)),
MyWidget(),
]
),
),
),
);
}
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SizedOverflowBox(
size: Size(double.infinity, 100),
child: Stack(
children: [
Container(color: Colors.amber, height: 100),
// Transform.translate(
// offset: Offset(0, -400),
// child: Container(color: Colors.lightBlue, height: 400, width: 80),
// ),
]
)
);
}
}
所以我的问题是:
- 如何在底部栏不移动且菜单位于其上方(浅蓝色容器)的情况下实现所需的结果;仅修改
MyWidget
而不是 MyApp
?
- 为什么在当前代码中将栏推到上面?
试试这个,运行 dartpad 中的这段代码。
它包含一个父项,三个子项,可以使用菜单按钮调用,
这段代码中使用的FloatingActionButton.extended
可以替换成任何自定义的Widget
,可以给onTap
点击的方法,
我使用了简单的 widgets
,让我知道您是在寻找类似的东西还是不同的东西。
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'I am Parent'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool showButtons = false;
var index = 0;
List<Widget> childList = [Child1(), Child2(), Child3()];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: childList[index],
),
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: [
Visibility(
visible: showButtons,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton.extended(
heroTag: 'btn1',
onPressed: () {
setState(() {
index = 0;
});
},
label: Text(
"Sub Btn1",
style: TextStyle(color: Colors.black),
),
elevation: 3,
backgroundColor: Colors.yellowAccent,
),
Padding(
padding: EdgeInsets.only(top: 3),
child: FloatingActionButton.extended(
heroTag: 'btn1',
onPressed: () {
setState(() {
index = 1;
});
},
label: Text(
"Sub Btn2",
style: TextStyle(color: Colors.black),
),
elevation: 3,
backgroundColor: Colors.yellowAccent,
)),
Padding(
padding: EdgeInsets.only(top: 3),
child: FloatingActionButton.extended(
heroTag: 'btn3',
onPressed: () {
setState(() {
index = 2;
});
},
label: Text(
"Sub Btn3",
style: TextStyle(color: Colors.black),
),
elevation: 3,
backgroundColor: Colors.yellowAccent,
))
],
),
),
RaisedButton(
onPressed: () {
setState(() {
showButtons = !showButtons;
});
},
child: Text("Self Contained"),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)),
color: Colors.yellow,
),
],
) // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class Child1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("I am Child 1"),
);
}
}
class Child2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("I am Child 2"),
);
}
}
class Child3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("I am Child 3"),
);
}
}
Overlay 和 OverlayEntry 可以帮助实现这一点:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: [
Expanded(child: Container(color: Colors.purple)),
MyWidget(),
]
),
),
),
);
}
}
class MyWidget extends StatelessWidget {
OverlayEntry? _overlayEntry;
_hideMenu() {
_overlayEntry?.remove();
}
_showMenu(BuildContext context) {
final overlay = Overlay.of(context);
_overlayEntry = OverlayEntry(
builder: (ctx) => Stack(
children: [
GestureDetector(
onTap: () => _hideMenu(),
child: Container(color: Colors.grey.withAlpha(100)),
),
Positioned(
bottom: 100,
left: 50,
child: Container(color: Colors.pink, height: 200, width: 50,),
),
],
)
);
overlay?.insert(_overlayEntry!);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _showMenu(context),
child: Container(color: Colors.amber, height: 100)
);
}
}
我正在尝试制作一个可扩展按钮,有点像可扩展 fab,只是它不是 fab,因为它不是浮动的。这是透视图的可扩展工厂:
不过,我想要实现的是拥有一个 独立 按钮,该按钮在其上方展开并带有一个菜单。自包含以粗体显示,因为我希望无需修改父结构即可轻松使用小部件。
因此,如果您将下面的代码复制粘贴到 dartpad 中,您会在底部看到一个黄色条。但是,如果您取消注释被注释的行,表示菜单展开,您会看到底部栏被推到顶部。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: [
Expanded(child: Container(color: Colors.purple)),
MyWidget(),
]
),
),
),
);
}
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SizedOverflowBox(
size: Size(double.infinity, 100),
child: Stack(
children: [
Container(color: Colors.amber, height: 100),
// Transform.translate(
// offset: Offset(0, -400),
// child: Container(color: Colors.lightBlue, height: 400, width: 80),
// ),
]
)
);
}
}
所以我的问题是:
- 如何在底部栏不移动且菜单位于其上方(浅蓝色容器)的情况下实现所需的结果;仅修改
MyWidget
而不是MyApp
? - 为什么在当前代码中将栏推到上面?
试试这个,运行 dartpad 中的这段代码。 它包含一个父项,三个子项,可以使用菜单按钮调用,
这段代码中使用的FloatingActionButton.extended
可以替换成任何自定义的Widget
,可以给onTap
点击的方法,
我使用了简单的 widgets
,让我知道您是在寻找类似的东西还是不同的东西。
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'I am Parent'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool showButtons = false;
var index = 0;
List<Widget> childList = [Child1(), Child2(), Child3()];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: childList[index],
),
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: [
Visibility(
visible: showButtons,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton.extended(
heroTag: 'btn1',
onPressed: () {
setState(() {
index = 0;
});
},
label: Text(
"Sub Btn1",
style: TextStyle(color: Colors.black),
),
elevation: 3,
backgroundColor: Colors.yellowAccent,
),
Padding(
padding: EdgeInsets.only(top: 3),
child: FloatingActionButton.extended(
heroTag: 'btn1',
onPressed: () {
setState(() {
index = 1;
});
},
label: Text(
"Sub Btn2",
style: TextStyle(color: Colors.black),
),
elevation: 3,
backgroundColor: Colors.yellowAccent,
)),
Padding(
padding: EdgeInsets.only(top: 3),
child: FloatingActionButton.extended(
heroTag: 'btn3',
onPressed: () {
setState(() {
index = 2;
});
},
label: Text(
"Sub Btn3",
style: TextStyle(color: Colors.black),
),
elevation: 3,
backgroundColor: Colors.yellowAccent,
))
],
),
),
RaisedButton(
onPressed: () {
setState(() {
showButtons = !showButtons;
});
},
child: Text("Self Contained"),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)),
color: Colors.yellow,
),
],
) // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class Child1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("I am Child 1"),
);
}
}
class Child2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("I am Child 2"),
);
}
}
class Child3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("I am Child 3"),
);
}
}
Overlay 和 OverlayEntry 可以帮助实现这一点:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: [
Expanded(child: Container(color: Colors.purple)),
MyWidget(),
]
),
),
),
);
}
}
class MyWidget extends StatelessWidget {
OverlayEntry? _overlayEntry;
_hideMenu() {
_overlayEntry?.remove();
}
_showMenu(BuildContext context) {
final overlay = Overlay.of(context);
_overlayEntry = OverlayEntry(
builder: (ctx) => Stack(
children: [
GestureDetector(
onTap: () => _hideMenu(),
child: Container(color: Colors.grey.withAlpha(100)),
),
Positioned(
bottom: 100,
left: 50,
child: Container(color: Colors.pink, height: 200, width: 50,),
),
],
)
);
overlay?.insert(_overlayEntry!);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _showMenu(context),
child: Container(color: Colors.amber, height: 100)
);
}
}