I.概要
Flutter
操作のヒントは非常に少ないがある SnackBar
、ので、 BottomSheet
より多くのスタイル、そして最終的にはうまく話す置きますDialog
Dialog
第二に、導入
-
スナックバー
スナックバーのソースコードは比較的簡単です
-
- コンストラクタ
CONST スナックバー({ キー、キー、 @required この .contentを、// プロンプト この .backgroundColor、// の背景色 この .actionを、// スナックバーテールボタンロールバック操作のいくつかのために 、この .duration = _kSnackBarDisplayDuration、// 彼らが滞在する時間を、デフォルトの4000ms この .animation、// アウトアニメーション })
- 例デモ
ユーザープロンプト我々は、操作を元に戻すためにユーザーがボタンを与えている間、それができる、修正、値を変更する機能を実装する必要がある場合はSnackBar
簡単に実現すること。
あるSnackBar
缶とfloatingActionButton
完璧なフィット感をするとき、ポップアップをブロックしていません、fab
クラス _PromptDemoPageStateが伸長状態<PromptDemoPage> { VARのカウント= 0 ; @オーバーライド ボイドinitState(){ super.initState(); } @オーバーライド ボイド廃棄(){ super.dispose(); } // インクリメントオペレータ 増加(){ SETSTATE(() =>カウント++ ); } // デクリメント演算 減少(){ SETSTATE(() => count-- )。 } _changeValue(BuildContextコンテキスト){ 増加する(); Scaffold.of(コンテキスト).showSnackBar(スナックバー( コンテンツ:テキスト(「現在の値が変更されています" )、 アクション:SnackBarAction(ラベル:' 撤销' 、onPressed:減)、 期間:所要時間(ミリ秒:2000 ))); } @オーバーライド ウィジェットビルド(BuildContextコンテキスト){ リターン足場( アプリケーションバー:アプリケーションバー( タイトル:テキスト(「プロンプトデモ」)、 )、 ボディ:カラム(子供: <ウィジェット> [ テキスト(' 現在の値:$のCOUNT '、スタイル:TEXTSTYLE(のfontSize:20.0 ))、 拡張( // 拡張を容易にするために、抽出法`snackBar`、そして上のボタンのリストの私の側 子供:リストビュー(
パディング:CONST EdgeInsets.symmetric(水平:12.0、の垂直数:8.0)、
子供:<ウィジェット> [ / / コンテキストを提供する必要性を備えるスナックバー、コンテキストではなく、コンテキスト足場ノードで、ビルダーの層ラップする必要があり ビルダー(ビルダー:(文脈)= > RaisedButton(onPressed:()=> _changeValue(コンテキスト)、子供を:テキスト(' 現在の値を変更します' )))、 ])) ])、 // ときスナックバーポップ、いくつかの距離で、ファブシフト floatingActionButton:ビルダー( ビルダー:(文脈) => FloatingActionButton(onPressed:()=> _changeValue(コンテキスト)、子供:アイコン(Icons.send)))、 ); } } - レンダリングは
探してくださいfab
変更と値:
- コンストラクタ
-
BottomSheet
BottomSheetは、これが示す、下部にあるポップアップメニューから、名前であることがわかりBottomSheetを二つの方法、すなわちでshowBottomSheetとshowModalBottomSheet方法は何の違いを呼び出していない、タイプの違いを示すための唯一の二つの方法が、showBottomSheetとFAB、アニメーションの組み合わせがあるshowModalBottomSheetいや、それの実用的な例を見てください。では、リストビューの増加BottomSheetのためのボタン、BottomSheetが必要なコンテキストをすることができない足場でコンテキスト、それはによって必要なBuilderのラッピング層、そして追加_showBottomSheetの方法を- 方法の例
_showBottomSheet(BuildContextコンテキスト){ showBottomSheet( コンテキスト:コンテキスト、 ビルダー:(コンテキスト) => リストビュー( // 生成するリスト・セレクタ 子供:List.generate(20は、
(指数) => インクウェル(
子:コンテナ(
アラインメント:Alignment.center、
高さ:60.0、
子供:テキスト(' + $ {インデックス1項} ' ))、 ONTAP:(){ プリント(' タップアイテム$ {指数+ 1} ' ); Navigator.pop(コンテキスト)。 } // ONTAP
)、//コンテナ )//インク入れ
)、//生成 );//リストビュー }showBottomSheetは交換しshowModalBottomSheetは内部が何らかの変更を加える必要はありません表示する別の方法です。
- 業績
私たちは二つの実験の効果を見てみましょう。 - 拡張は
見ることができますshowBottomSheetは、画面全体を埋め、次に続く製造工場に行ってきましたでしょうアプリケーションバーながら、下の位置をshowModalBottomSheetは、高さが画面の半分の高さを超えるのではなく、表示さファブその隠さによって。我々は唯一の2-3表示する必要がある場合は項目を、しかし方法で、ちょうどshowModalBottomSheet高さが高すぎる、我々はできるのListView小包の外層コンテナをした後、指定した高さにします
_showModalBottomSheet(BuildContextコンテキスト){ (モーダルボトムシートを表示 コンテキスト:コンテキスト、 ビルダー:(文脈) => コンテナ( 子供:リストビュー( 子供:List.generate( 2 、 (指数) => インクつぼ( 子:コンテナ(アラインメント:Alignment.center、高さ:60.0、子:テキスト(' アイテム$ {指数+ 1} ' ))、 ONTAP:(){ プリント(' タップアイテム$ {指数+ 1} ' ); Navigator.pop(コンテキスト)。 })、 ))、 高さ:120 、 )、 ); }
- 高さを変更する効果:
- 高さを変更する効果:
- 方法の例
-
ダイアログ
相对于 SnackBar和 BottomSheet,Dialog的使用场景相对会更多,在 MaterialDesign下,
Dialog主要有 3 种:AlertDialog,SimpleDialog和 AboutDialog,当然在 Cupertino风格下也有相应的 Dialog,因为这个系列以 MaterialDesign风格为主,所以
Cupertiono等下次有时间再写吧。
-
AlertDialog
在 ListView中增加一个 AlertDialog的按钮,用于点击显示 AlertDialog用,然后加入显示 AlertDilaog的方法,并将按钮的 onPressed指向该方法,Dialog的 context可以是 Scaffold下的 context,所以不需要用 Builder来包裹一层。- 示例代码
_showAlertDialog() { showDialog( // 设置点击 dialog 外部不取消 dialog,默认能够取消 barrierDismissible: false, context: context, builder: (context) => AlertDialog( title: Text('我是个标题...嗯,标题..'), titleTextStyle: TextStyle(color: Colors.purple), // 标题文字样式 content: Text(r'我是内容\(^o^)/~, 我是内容\(^o^)/~, 我是内容\(^o^)/~'), contentTextStyle: TextStyle(color: Colors.green), // 内容文字样式 backgroundColor: CupertinoColors.white, elevation: 8.0, // 投影的阴影高度 semanticLabel: 'Label', // 这个用于无障碍下弹出 dialog 的提示 shape: Border.all(), // dialog 的操作按钮,actions 的个数尽量控制不要过多,否则会溢出 `Overflow` actions: <Widget>[ // 点击增加显示的值 FlatButton(onPressed: increase, child: Text('点我增加')), // 点击减少显示的值 FlatButton(onPressed: decrease, child: Text('点我减少')), // 点击关闭 dialog,需要通过 Navigator 进行操作 FlatButton(onPressed: () => Navigator.pop(context), child: Text('你点我试试.')), ], )); }
-
效果
- 示例代码
-
SimpleDialog
SimpleDialog相比于 AlertDialog少了 content和 action参数,多了 children属性,需要传入 Widget列表,那就可以自定义全部内容了。那我们这里就实现一个性别选择的 Dialog,选择后通过 Taost提示选择的内容,Taost就是之前导入的第三方插件,只要实现 children 是个列表选择器就可以了。
- 示例代码
_showSimpleDialog() { showDialog( barrierDismissible: false, context: context, builder: (context) => SimpleDialog( title: Text('我是个比较正经的标题...\n选择你的性别'), // 这里传入一个选择器列表即可 children: _genders .map((gender) => InkWell( child: Container(height: 40.0, child: Text(gender), alignment: Alignment.center), onTap: () { Navigator.pop(context); Fluttertoast.showToast(msg: '你选择的性别是 $gender'); }, )) .toList(), )); }
-
效果
- 示例代码
-
-
-
AboutDialog
AboutDialog主要是用于展示你的 App或者别的相关东西的内容信息的,平时用的比较少,显示 AboutDialog有两种方式可以展示,一种是前面一样的 showDialog方法,传入一个 AboutDialog实例,还有中方法是直接调用 showAboutDialog方法。我们还是一样在列表加个按钮,并指向显示 AboutDialog的事件。
- 示例代码
_showAboutDialog() { showDialog( barrierDismissible: false, context: context, builder: (context) => AboutDialog( // App 的名字 applicationName: 'Flutter 入门指北', // App 的版本号 applicationVersion: '0.1.1', // App 基本信息下面会显示一行小字,主要用来显示版权信息 applicationLegalese: 'Copyright: this is a copyright notice topically', // App 的图标 applicationIcon: Icon(Icons.android, size: 28.0, color: CupertinoColors.activeBlue), // 任何你想展示的 children: <Widget>[Text('我是个比较正经的对话框内容...你可以随便把我替换成任何部件,只要你喜欢(*^▽^*)')], )); }
也可以通过 showAboutDialog实现同样的效果
_showAboutDialog() { showAboutDialog( context: context, applicationName: 'Flutter 入门指北', applicationVersion: '0.1.1', applicationLegalese: 'Copyright: this is a copyright notice topically', applicationIcon: Image.asset('images/app_icon.png', width: 40.0, height: 40.0), children: <Widget>[Text('我是个比较正经的对话框内容...你可以随便把我替换成任何部件,只要你喜欢(*^▽^*)')], ); }
-
最后的效果:
- 拓展
AboutDialog会自带两个按钮 VIEW LICENSES和 CLOSE,VIEW LICENSES会跳转一个 Flutter Licenses的网页,CLOSE会关闭,至于为什么是英文的,是因为我们没有设置语言的原因,这个涉及到多语言。
- 示例代码
-
三,Dialog 状态保持
假如有个需求,需要在弹出的 Dialog显示当前被改变的值,然后通过按钮可以修改这个值 ,该如何实现。相信很多小伙伴都会这么认为,通过 setState来修改不就行了吗,没错,我一开始的确这么去实现的,我们先看下代码好了,增加一个 DialogState按钮,然后指向对应的点击事件。
- 示例代码
_showStateDialog() { showDialog( context: context, barrierDismissible: false, builder: (context) => SimpleDialog( title: Text('我这边能实时修改状态值'), contentPadding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), children: <Widget>[ Text('当前的值是: $_count', style: TextStyle(fontSize: 18.0)), Padding( padding: const EdgeInsets.symmetric(vertical: 12.0), child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ RaisedButton( onPressed: increase, child: Text('点我自增'), ), RaisedButton( onPressed: decrease, child: Text('点我自减'), ), RaisedButton( onPressed: () => Navigator.pop(context), child: Text('点我关闭'), ) ]), ) ], )); }
-
效果
- 遇到问题
怎么 Dialog的值不改变呢,明明界面上的已经修改了啊。所以说图样图森破咯,看下官方对 showDialog方法的解释吧
/// This function takes a `builder` which typically builds a [Dialog] widget. /// Content below the dialog is dimmed with a [ModalBarrier]. The widget /// returned by the `builder` does not share a context with the location that /// `showDialog` is originally called from. Use a [StatefulBuilder] or a /// custom [StatefulWidget] if the dialog needs to update dynamically.
- 解决办法
所以解决的方法很明确,对上面的代码进行修改,在外层嵌套一个 StatefulBuilder部件
_showStateDialog() { showDialog( context: context, barrierDismissible: false, // 通过 StatefulBuilder 来保存 dialog 状态 // builder 需要传入一个 BuildContext 和 StateSetter 类型参数 // StateSetter 有一个 VoidCallback,修改状态的方法在这写 builder: (context) => StatefulBuilder( builder: (context, dialogStateState) => SimpleDialog( title: Text('我这边能实时修改状态值'), contentPadding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), children: <Widget>[ Text('当前的值是: $_count', style: TextStyle(fontSize: 18.0)), Padding( padding: const EdgeInsets.symmetric(vertical: 12.0), child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ RaisedButton( // 通过 StatefulBuilder 的 StateSetter 来修改值 onPressed: () => dialogStateState(() => increase()), child: Text('点我自增'), ), RaisedButton( onPressed: () => dialogStateState(() => decrease()), child: Text('点我自减'), ), RaisedButton( onPressed: () => Navigator.pop(context), child: Text('点我关闭'), ) ]), ) ], ))); }
-
修改效果
然后再运行下,可以看到 dialog和界面的值保持一致了