朋也的博客 » 首页 » 文章
作者:朋也
日期:2019-07-18
类别:flutter学习笔记
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
先上图
先写几个按钮,通过点击来显示一些弹层
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo'),
),
body: Builder(
builder: (context) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text("Show Modal Buttom Sheet"),
onPressed: () => _onButtonPressed(context)),
RaisedButton(
child: const Text('Show toast'),
onPressed: () => _showToast(context, "我是一个toast"),
),
RaisedButton(
child: const Text('Show confirm'),
onPressed: () => _showConfirm(context, "我是一个confirm"),
),
RaisedButton(
child: const Text('Show input dialog'),
onPressed: () => _showInputDialog(context),
),
],
)),
),
);
}
这个功能还是很常用的,比如一些详情页面的右上角都会有三个小点,点开之后可以选择一些分享,浏览器打开,复制等功能,下面在flutter里实现一下这个功能
这种弹层在flutter里是一个方法渲染出来的 showModalBottomSheet()
它里面有两个参数,context
builder
弹出的层长啥样,就是在 builder 里定义的,跟写组件没什么区别
void _onButtonPressed(BuildContext _context) {
showModalBottomSheet(
context: _context,
builder: (__context) {
return Container(
color: Color(0xff737373),
height: 185,
child: Container(
margin: EdgeInsets.fromLTRB(8, 0, 8, 8),
decoration: BoxDecoration(
color: Theme.of(__context).canvasColor,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(10),
topRight: const Radius.circular(10),
bottomLeft: const Radius.circular(10),
bottomRight: const Radius.circular(10),
)),
child: Column(
children: <Widget>[
ListTile(
leading: Icon(Icons.share),
title: Text("分享"),
onTap: () => _modalItemPressed(_context, "分享")),
Divider(height: 0),
ListTile(
leading: Icon(Icons.favorite),
title: Text("收藏"),
onTap: () => _modalItemPressed(_context, "收藏")),
Divider(height: 0),
ListTile(
leading: Icon(Icons.open_in_browser),
title: Text("浏览器打开"),
onTap: () => _modalItemPressed(_context, "浏览器打开")),
],
),
),
);
});
}
void _modalItemPressed(BuildContext _context, String title) {
Navigator.pop(_context);
_showToast(_context, "你点击了:" + title);
}
再结合点击按钮事件,就可以实现动图中的效果了
在Material标准中,Toast的实现就是 Snack Bar
它需要上面文 context
, 所以要从上游传过来
注意,显示toast的这个上下文应该是父组件的 context, 当使用有状态的组件时,父类中也有一个 context, 不要用这个 context, 最好是从当前页面的父组件里传过来
这个地方我碰到了坑,就是因为乱用 context, 因为当页面点击按钮显示 Modal Bottom Sheet 的组件时,这个组件也有一个 builder 方法,这方法中也有一个 context, 当点击其中一项后,这个弹层就隐藏掉了,这时候如果用这个组件的context,程序就会报错,所以这个地方一定要注意
void _showToast(BuildContext _context, String text) {
final scaffold = Scaffold.of(_context);
scaffold.showSnackBar(
SnackBar(
content: Text(text),
action: SnackBarAction(
label: 'UNDO', onPressed: scaffold.hideCurrentSnackBar),
),
);
}
链接文原: https://atjiu.github.io/2019/07/18/flutter-dialogs/
void _showConfirm(BuildContext _context, String text) {
showDialog<void>(
context: _context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('信息'),
content: Text(text),
actions: <Widget>[
FlatButton(
child: const Text('取消'),
onPressed: () {
Navigator.of(context).pop();
_showToast(_context, "你点了取消");
},
),
FlatButton(
child: const Text('确定'),
onPressed: () {
Navigator.of(context).pop();
_showToast(_context, "你点了确定");
},
),
],
);
},
);
}
有了确认对话框,肯定少不了可以输入信息的对话框
void _showInputDialog(BuildContext _context) {
String _name = "";
showDialog<String>(
context: _context,
barrierDismissible: false,
// dialog is dismissible with a tap on the barrier
builder: (BuildContext __context) {
return AlertDialog(
title: Text('输入姓名'),
content: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
autofocus: true,
decoration:
new InputDecoration(labelText: '姓名', hintText: '输入姓名'),
onChanged: (value) { // 当input里值有变动的时候,就会触发这个方法
_name = value;
},
))
],
),
actions: <Widget>[
FlatButton(
child: Text('取消'),
onPressed: () {
Navigator.of(context).pop();
_showToast(_context, "你什么都没有写~");
},
),
FlatButton(
child: Text('确定'),
onPressed: () {
if (_name == "") {
_showToast(_context, "写点什么!");
} else {
Navigator.of(context).pop();
_showToast(_context, "你输入的姓名为:$_name");
}
},
),
],
);
},
);
}
接链文原: https://atjiu.github.io/2019/07/18/flutter-dialogs/
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.purple),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() => Home();
}
class Home extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo'),
),
body: Builder(
builder: (context) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text("Show Modal Buttom Sheet"),
onPressed: () => _onButtonPressed(context)),
RaisedButton(
child: const Text('Show toast'),
onPressed: () => _showToast(context, "我是一个toast"),
),
RaisedButton(
child: const Text('Show confirm'),
onPressed: () => _showConfirm(context, "我是一个confirm"),
),
RaisedButton(
child: const Text('Show input dialog'),
onPressed: () => _showInputDialog(context),
),
],
)),
),
);
}
void _onButtonPressed(BuildContext _context) {
showModalBottomSheet(
context: _context,
builder: (__context) {
return Container(
color: Color(0xff737373),
height: 185,
child: Container(
margin: EdgeInsets.fromLTRB(8, 0, 8, 8),
decoration: BoxDecoration(
color: Theme.of(__context).canvasColor,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(10),
topRight: const Radius.circular(10),
bottomLeft: const Radius.circular(10),
bottomRight: const Radius.circular(10),
)),
child: Column(
children: <Widget>[
ListTile(
leading: Icon(Icons.share),
title: Text("分享"),
onTap: () => _modalItemPressed(_context, "分享")),
Divider(height: 0),
ListTile(
leading: Icon(Icons.favorite),
title: Text("收藏"),
onTap: () => _modalItemPressed(_context, "收藏")),
Divider(height: 0),
ListTile(
leading: Icon(Icons.open_in_browser),
title: Text("浏览器打开"),
onTap: () => _modalItemPressed(_context, "浏览器打开")),
],
),
),
);
});
}
void _modalItemPressed(BuildContext _context, String title) {
Navigator.pop(_context);
_showToast(_context, "你点击了:" + title);
}
void _showToast(BuildContext _context, String text) {
final scaffold = Scaffold.of(_context);
scaffold.showSnackBar(
SnackBar(
content: Text(text),
action: SnackBarAction(
label: 'UNDO', onPressed: scaffold.hideCurrentSnackBar),
),
);
}
void _showConfirm(BuildContext _context, String text) {
showDialog<void>(
context: _context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('信息'),
content: Text(text),
actions: <Widget>[
FlatButton(
child: const Text('取消'),
onPressed: () {
Navigator.of(context).pop();
_showToast(_context, "你点了取消");
},
),
FlatButton(
child: const Text('确定'),
onPressed: () {
Navigator.of(context).pop();
_showToast(_context, "你点了确定");
},
),
],
);
},
);
}
void _showInputDialog(BuildContext _context) {
String _name = "";
showDialog<String>(
context: _context,
barrierDismissible: false,
// dialog is dismissible with a tap on the barrier
builder: (BuildContext __context) {
return AlertDialog(
title: Text('输入姓名'),
content: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
autofocus: true,
decoration:
new InputDecoration(labelText: '姓名', hintText: '输入姓名'),
onChanged: (value) {
_name = value;
},
))
],
),
actions: <Widget>[
FlatButton(
child: Text('取消'),
onPressed: () {
Navigator.of(context).pop();
_showToast(_context, "你什么都没有写~");
},
),
FlatButton(
child: Text('确定'),
onPressed: () {
if (_name == "") {
_showToast(_context, "写点什么!");
} else {
Navigator.of(context).pop();
_showToast(_context, "你输入的姓名为:$_name");
}
},
),
],
);
},
);
}
}