We often need to customize dialogs according to different daily needs, and the small dishes encountered some minor problems in the process of trying, briefly record the summary;

Dialog

Q1. Soft keyboard blocks dialog boxes containing text boxes

When a Dialog with a text box is customized, the soft keyboard will partially block the Dialog box when the text box gets the focus. However, when an AlertDialog is replaced with a small menu, the Dialog box will float upwards when the text box gets the focus to avoid blocking by the soft keyboard.

return Material( type: MaterialType.transparency, child: Stack(children: [ Center( child: Container( decoration: BoxDecoration(color: color.white, borderRadius: borderRadius. Circular (20.0)), margin: EdgeInsets. Only (left: Symmetric (horizontal: 20.0, vertical: 25.0), child: Padding(Padding: EdgeInsets. Symmetric (horizontal: 20.0, vertical: 25.0), child: symmetric(horizontal: 20.0, vertical: 25.0) Column(mainAxisSize: mainAxisSize. Min, children: [Text(' bill name ', style: TextStyle(fontSize: 16.0)), _nameWid(), Row(children: [Expanded(Child: _actionButtons(0))), SizedBox(Width: 15.0), Expanded(child: _actionButtons(1)) ]) ])))) ])); Future<void> _showBillNameDialog() async { await showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return BillNameDialog(onCancelEvent: () { Navigator.pop(context); }, onSureEvent: (name) { Navigator.pop(context); }); }); }Copy the code

A1. Scaffold & resizeToAvoidBottomInset

For custom dialogs with text boxes, Material nesting is used in the outer layer of the Scaffold. Default Scaffold resizeToAvoidBottomPadding/resizeToAvoidBottomInset to true, when set to false, the text box for focus, will still be soft keyboard; Because in the fixed scenario can cooperate resizeToAvoidBottomPadding realize whether be soft keyboard effect;

ResizeToAvoidBottomPadding is mainly used for its own Widget will avoid being other window shade; The avoidbottom inset resizeto is more recommended after Flutter 1.1.9.

class BillNameDialog extends Dialog { final Function onCancelEvent; final Function onSureEvent; BillNameDialog({Key key, @required this.onCancelEvent, @required this.onSureEvent}); @override Widget build(BuildContext context) { return Material( type: MaterialType.transparency, child: Scaffold( backgroundColor: Colors.transparent, resizeToAvoidBottomPadding: true, body: Stack(children: [ Center( child: Container(decoration: BoxDecoration(color: color.white, borderRadius: borderRadius. Circular (20.0)), margin: EdgeInsets. Only (left: 20.0, right: 20.0), child: Padding(Padding: EdgeInsets. Symmetric (horizontal: 20.0, vertical: 20.0) 25.0), child: Column(mainAxisSize: mainAxisSize. Min, children: [Text(' bill name ', style: TextStyle(fontSize: 16.0)), _nameWid(), Row(children: [Expanded(Child: _actionButtons(0))), SizedBox(Width: 15.0), Expanded(child: _actionButtons(1)) ]) ])))) ]))); } _nameWid() {return Container(margin: EdgeInsets. Symmetric (vertical: 25.0), child: TextField(Controller: TextEditingController(), decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric(horizontal: 15.0), hintText: 'Create order name ', hintStyle: TextStyle(fontSize: 14.0), border: OutlineInputBorder(borderRadius: BorderRadius. Circular (10.0), borderSide: borderSide. None), filled: true, fillColor: Color(0xFFf1efe5)))); } _actionButtons(type) { return InkWell( child: Container( alignment: Alignment.center, decoration: BoxDecoration( color: type == 0 ? Color(0xFF1E1E1E) : Colors.deepOrange, border: Border.all( color: type == 0 ? Color(0xFF1E1E1E) : Colors. DeepOrange), borderRadius: borderRadius. Circular (6.0)), Child: Padding(Padding: EdgeInsets. Horizontal: 12.0), child: Text(type == 0? Horizontal: 12.0), style: TextStyle(color: color.white, fontSize: 15.0)))), onTap: () {if (type = = 0) {onCancelEvent (); } else { onSureEvent(); }}); }}Copy the code

Q2. Dialog box for status update

Select * from * Dialog; select * from * Dialog; select * from * Dialog;

class TypeListDialog extends Dialog { @override Widget build(BuildContext context) { return Material( type: MaterialType.transparency, child: Center( child: Container( decoration: BoxDecoration(color: Colors. White, borderRadius: borderRadius. Circular (20.0)), Margin: EdgeInsets. Symmetric (horizontal: 25.0), child: Symmetric (Horizontal: 20.0, vertical: 25.0), child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ _itemTag(allType, null, 0), SizedBox(height: 15.0), _wrapListTag(levelType, this.data), SizedBox(height: 10.0), Row(mainAxisAlignment: MainAxisAlignment.end, children: [ _bottomButton(0, context), SizedBox(width: 15.0), _bottomButton(1, context)])]))))); } _wrapListTag(type, tagList) { List<Widget> tagWid = []; if (tagList ! = null && tagList.length > 0) { for (int i = 0; i < tagList.length; i++) { tagWid.add(_itemTag(type, tagList, i)); } else {tagwid. add(Container(width: 0.0, height: 0.0)); } return Wrap(children: tagWid, spacing: 15.0, runSpacing: 15.0); } _bottomButton(type, context) { return InkWell( child: Container( decoration: BoxDecoration(color: type == 0 ? Colors.black : Colors.deepOrange, border: Border.all(color: type == 0 ? Colors.black : Colors. DeepOrange), borderRadius: borderRadius. Circular (6.0)), Child: Padding(Padding: EdgeInsets. Horizontal: 12.0), child: Text(type == 0? 'Cancel' : 'Sure', style: TextStyle(color: color.white, fontSize: 16.0)))), onTap: () {}); } } Future<void> _showTypeListDialog() async { await showDialog(context: context, barrierDismissible: false, builder: (BuildContext context) { return TypeListDialog(data: levelList); }); }Copy the code

A2. Create a StatefulBuilder constructor

WidgetBuilder creates a StatefulBuilder stateful constructor, passing state to the Dialog. WidgetBuilder creates a StatefulBuilder stateful constructor, passing state to the Dialog.

final Function state; TypeListDialog({Key key, this.data, @required this.state, @required this.onSelectEvent}); _itemTag(type, list, index) { bool _isChecked = false; if (allType == type) { _isChecked = isAllChecked; } else { _isChecked = list[index].isChecked; } return InkWell( key: GlobalKey(), child: Container( decoration: BoxDecoration(color: _isChecked ? Colors.deepOrange : Colors.white, border: Border.all(color: _isChecked ? Colors.deepOrange : Color.black), borderRadius: borderRadius. Circular (18.0)), Child: Padding(Padding: EdgeInsets. Only (top: 5.0, bottom: 5.0, left: 16.0, right: 16.0), child: Text(type == allType? 'all' : list[index]. White: Colors. Black, fontSize: 16.0)))), onTap: () { if (type == levelType) { List.generate(data.length, (curIndex) { if (index == curIndex) { data[curIndex].isChecked = ! data[curIndex].isChecked; if (data[curIndex].isChecked) { levelBackList.add(data[curIndex].name); }}}); state(() {}); }}); } Future<void> _showTypeListDialog() async { await showDialog(context: context, barrierDismissible: false, builder: (BuildContext context) { return StatefulBuilder(builder: (context, state) => TypeListDialog(state: state, data: levelList)); }); }Copy the code

Q3. Dialog callback is passed as a parameter

How to pass multiple arguments in a callback method when customizing a Dialog?

A3. The receiving method matches the Function transfer parameter

The trick is to pass two lists in the callback method of the Dialog and match two arguments in the callback method of the receive; The side dish is simply a function method;

OnSelectEvent (levelBackList, ['a', 'b', 'c']); Future<void> _showTypeListDialog() async {await showDialog(context: context, barrierdistransmissible: false, builder: (BuildContext context) => StatefulBuilder( builder: (context, state) => TypeListDialog( state: state, data: levelList, onSelectEvent: (list1, list2) { print('list1=$list1, list2=$list2'); Toast.show('list1=$list1, list2=$list2', context, duration: Toast.LENGTH_SHORT, gravity: Toast.BOTTOM); }))); }Copy the code

Q4. AppBar return button

The side dishes are being rewrittenAppBarHow do I cancel the default back button?

A4. Material | automaticallyImplyLeading

There are several ways to remove the back icon in front of the AppBar;

  • Scaffold outer layer nested Material;
@override
Widget build(BuildContext context) {
  return Material(
      child: Scaffold(
          appBar: AppBar(title: Text('Dialog Page')),
          body: _bodyWid()));
}
Copy the code
  • In the AppBar automaticallyImplyLeading attribute is set to false;
@override
Widget build(BuildContext context) {
  return Scaffold(
      appBar: AppBar(title: Text('Dialog Page'), automaticallyImplyLeading: false),
      body: _bodyWid());
}
Copy the code
  • The WidgetBuilder is set to MaterialPageRoute mode when the dynamic route jumps. Note that push needs to be pushReplacement/pushAndRemoveUntil.
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => DialogPage()));
Copy the code


Custom Dialog case source code


Xiao CAI is not familiar with the application of Flutter, and many common scenes are not properly handled. Xiao CAI will simply record small daily problems and learn them step by step. If there are mistakes, please give more guidance!

Source: Little Monk A Ce