【发布时间】:2021-02-27 15:34:59
【问题描述】:
【问题讨论】:
标签: android flutter flutter-layout
【问题讨论】:
标签: android flutter flutter-layout
是的,您必须制作自己的自定义应用 Bar
只需做一件事,将所有内容放入堆栈
Stack(
children:[
Position(
top:0,
left:0
child:YourLizardWidget()
),
Position(
top:0,
left:0
right:0
child:YourAppBar()
),
])
可能会起作用
【讨论】:
使用应用程序的Scaffold 的drawer 的另一种解决方案。
注意:如果您已经使用drawer,您也可以使用endDrawer。
此解决方案为左侧动画的幻灯片添加了一个不错的小触感。 (从右侧滑动到末端抽屉)
关于解决方案的几点说明:
AppBar 中,我指定了leading: new Container() 来隐藏汉堡菜单并为蜥蜴留出一些空间。MyLizardMessage 中,我使用Column 和verticalDirection: VerticalDirection.up,这样我的图像(使用OverflowBox 显示在圆角Container 的顶部)import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
);
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: new Container(),
title: Text('Mes larfeuils'),
),
drawer: MyLizardMessage(),
body: MyContent(),
);
}
}
class MyLizardMessage extends StatelessWidget {
const MyLizardMessage({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
verticalDirection: VerticalDirection.up,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 0.0),
child: Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.black87,
),
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
child: Text(
'Cupim beef ribs t-bone, shank short loin chicken pork belly prosciutto ribeye hamburger doner pork chop leberkas. '),
),
),
IntrinsicWidth(
child: Container(
height: 82.0,
child: OverflowBox(
maxHeight: 85.0,
child: Image.asset(
'images/lizard.png',
height: 85.0,
),
),
),
),
],
);
}
}
class MyContent extends StatelessWidget {
const MyContent({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
'Bacon ipsum dolor amet corned beef pork pork loin, chislic tri-tip picanha beef leberkas short ribs sirloin salami buffalo drumstick. Shankle chislic sirloin pork t-bone short ribs swine sausage hamburger chicken tail. Ham hock doner pancetta, jowl hamburger bacon prosciutto. Strip steak picanha jerky chislic. Strip steak prosciutto beef, pastrami corned beef t-bone frankfurter bacon rump sausage swine filet mignon fatback pork loin. Swine shank short ribs ham porchetta.',
),
const SizedBox(height: 16.0),
ElevatedButton(
onPressed: () => Scaffold.of(context).openDrawer(),
child: Text('Open message dialog')),
const SizedBox(height: 16.0),
Text(
'T-bone venison picanha, corned beef meatloaf bacon buffalo sirloin biltong pancetta strip steak. Ham hock meatloaf tongue pastrami t-bone. Flank prosciutto shoulder chicken, turducken biltong hamburger short ribs beef buffalo brisket chislic filet mignon. Short ribs pork chop jowl jerky, beef ribs sirloin beef kevin landjaeger boudin chislic shankle. Tail pastrami swine drumstick, landjaeger turkey pig ground round.',
),
],
),
);
}
}
【讨论】:
这是另一个使用 OverlayEntry 的解决方案。
这一次,您可以定义消息出现时的动画。但是消息是非模态的。您仍然可以使用消息下方的应用程序 UI。在上面的截屏视频中,我通过单击ElevatedButton 打开消息,然后使用相同的按钮和消息中的关闭图标将其关闭。我还展示了AppBar 操作按钮在显示消息时也是可点击的。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
);
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: new Container(),
title: Text('Mes larfeuils'),
actions: [IconButton(icon: Icon(Icons.add), onPressed: () {})],
),
body: MyContent(),
);
}
}
class MyLizardMessage extends StatefulWidget {
final VoidCallback onClose;
const MyLizardMessage({
Key key,
this.onClose,
}) : super(key: key);
@override
_MyLizardMessageState createState() => _MyLizardMessageState();
}
class _MyLizardMessageState extends State<MyLizardMessage>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<Offset> position;
@override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 300));
position = Tween<Offset>(begin: Offset(-1.0, 0.0), end: Offset.zero)
.animate(CurvedAnimation(parent: controller, curve: Curves.easeInOut));
controller.forward();
}
@override
Widget build(BuildContext context) {
return SlideTransition(
position: position,
child: Column(
verticalDirection: VerticalDirection.up,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Material(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 0.0),
child: Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.black87,
),
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
'Cupim beef ribs t-bone, shank short loin chicken pork belly prosciutto ribeye hamburger doner pork chop leberkas. ',
style: TextStyle(inherit: false),
),
),
GestureDetector(
onTap: () => widget.onClose?.call(),
child: Icon(Icons.close),
),
],
),
),
),
),
IntrinsicWidth(
child: Container(
height: 82.0,
child: OverflowBox(
maxHeight: 85.0,
child: Image.asset(
'images/lizard.png',
height: 85.0,
),
),
),
),
],
),
);
}
}
class MyContent extends StatefulWidget {
const MyContent({
Key key,
}) : super(key: key);
@override
_MyContentState createState() => _MyContentState();
}
class _MyContentState extends State<MyContent> {
OverlayEntry _overlayEntry;
bool get _isMessageShown => _overlayEntry != null && _overlayEntry.mounted;
OverlayEntry _createOverlayEntry() {
return OverlayEntry(
builder: (context) {
final width = MediaQuery.of(context).size.width;
return Positioned(
top: 0,
left: 0,
width: width,
child: MyLizardMessage(onClose: () => _hideMessage()),
);
},
opaque: false,
);
}
_showMessage() {
_overlayEntry = _createOverlayEntry();
Overlay.of(context).insert(_overlayEntry);
setState(() {});
}
_hideMessage() {
_overlayEntry?.remove();
_overlayEntry = null;
setState(() {});
}
_toggleMessage() => _isMessageShown ? _hideMessage() : _showMessage();
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
'Bacon ipsum dolor amet corned beef pork pork loin, chislic tri-tip picanha beef leberkas short ribs sirloin salami buffalo drumstick. Shankle chislic sirloin pork t-bone short ribs swine sausage hamburger chicken tail. Ham hock doner pancetta, jowl hamburger bacon prosciutto. Strip steak picanha jerky chislic. Strip steak prosciutto beef, pastrami corned beef t-bone frankfurter bacon rump sausage swine filet mignon fatback pork loin. Swine shank short ribs ham porchetta.',
),
const SizedBox(height: 16.0),
ElevatedButton(
onPressed: () => _toggleMessage(),
child: Text(_isMessageShown
? 'Close message dialog'
: 'Open message dialog')),
const SizedBox(height: 16.0),
Text(
'T-bone venison picanha, corned beef meatloaf bacon buffalo sirloin biltong pancetta strip steak. Ham hock meatloaf tongue pastrami t-bone. Flank prosciutto shoulder chicken, turducken biltong hamburger short ribs beef buffalo brisket chislic filet mignon. Short ribs pork chop jowl jerky, beef ribs sirloin beef kevin landjaeger boudin chislic shankle. Tail pastrami swine drumstick, landjaeger turkey pig ground round.',
),
],
),
);
}
}
【讨论】:
您可以执行以下操作:
class NextPage extends StatefulWidget {
@override
_NextPageState createState() => _NextPageState();
}
class _NextPageState extends State<NextPage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Colors.white,
appBar: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width,200),
child: Container(
child: Stack(
alignment: Alignment.topLeft,
children: <Widget>[
Container(color: Colors.red,width: MediaQuery.of(context).size.width,height: 100,),
Container(width: 100,height: 200,color: Colors.blue,),
],
),
),
),
body: Container(color: Colors.amber,),
),
);
}
}
我添加了一个 PreferredSize 小部件。它就像一个定义应用栏最大宽度和高度的容器。
我添加了extendBodyBehindAppBar: true 属性,以便正文部分将从屏幕顶部开始,而不是从应用栏下方开始。
然后我简单地将我的自定义应用栏添加为子属性。
这是上面代码的结果。 (红色容器将是您的自定义应用栏,蓝色容器可以替换为您的资产)
【讨论】: