提供了一个完整可复用的弹出式底部输入框。
先看效果图
代码实现
第一页代码 main_bottom_input.dart
import 'package:flutter/material.dart';
import 'bottom_input/input_dialog.dart';
void main() => runApp(MaterialApp(home: InputHomeWidget()));
class InputHomeWidget extends StatefulWidget {
@override
_InputHomeWidgetState createState() => _InputHomeWidgetState();
}
class _InputHomeWidgetState extends State<InputHomeWidget> {
String _inputString = "";
@override
Widget build(BuildContext context) {
return Scaffold(
/**弹出键盘会导致bottomInset值变化,可以通过MediaQuery获取到各种值。
resizeToAvoidBottomInset:true(默认值),
表示根据变化重新Build,页面会被顶到键盘上,当然也可以通过scollView处理 **/
resizeToAvoidBottomInset: false,
appBar: AppBar(title: Text("底部输入框"),),
body: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FlatButton(
color: Colors.yellow,
onPressed: _input,
child: Text("弹出底部输入框"),
),
Expanded(child: Text("结果:$_inputString")),
Text("底部文案"),
Container(height: 100, width: 20,)
],
),
);
}
void _input() {
InputDialog.show(context).then((value) {
setState(() {
_inputString = value;
});
});
}
}
输入框Dialog代码 input_dialog.dart
这个InputOverlay是从Dialog抄过来的。Flutter中的页面都是route,可以设置route的各种属性:背景色,页面切换动画。这里重点是barrierColor设置背景色。dialog会有默认半透明。我们这个地方需要全透明,但记住不能设置 0x00000000,看报错是说全透明,有页面切换的错误。。
这个ModalRoute属性的各种玩法就很多了,可以改改属性试试各种效果
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'input_widget.dart';
class InputDialog {
static Future<String> show(BuildContext context) async {
return Navigator.of(context).push(InputOverlay());
}
}
class InputOverlay extends ModalRoute<String> {
@override
Duration get transitionDuration => Duration(milliseconds: 200);
@override
bool get opaque => false;
@override
bool get barrierDismissible => true;
@override
Color get barrierColor => const Color(0x01000000);
@override
String get barrierLabel => null;
@override
bool get maintainState => true;
@override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return InputWidget();
}
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return FadeTransition(
opacity: CurvedAnimation(
parent: animation,
curve: Curves.easeOut,
),
child: child,
);
}
}
输入框Widget代码 input_widget.dart
页面由两部分组成 上面的透明区域,点击可消失页面。底部的输入框区域。这个地方要注意resizeToAvoidBottomInset不可以设置成false了,否则顶不起来输入框哦
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class InputWidget extends StatefulWidget {
InputWidget({Key key}) : super(key: key);
@override
_InputWidgetState createState() => _InputWidgetState();
}
class _InputWidgetState extends State<InputWidget> {
@override
Widget build(BuildContext context) {
TextEditingController editingController = TextEditingController();
return Scaffold(
backgroundColor: Colors.transparent,
// resizeToAvoidBottomInset: false,
body: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: GestureDetector(
onTapDown: (_) => Navigator.of(context).pop(),
child: Container(
color: Colors.transparent,
)),
),
SafeArea(
child: Container(
color: Colors.white,
child: Row(
children: <Widget>[
Container(
width: 20,
),
Expanded(
child: Container(
margin: EdgeInsets.only(top: 10, bottom: 10),
decoration: BoxDecoration(
color: Color(0xfff6f8fb),
borderRadius:
BorderRadius.all(Radius.circular(20))),
alignment: Alignment.center,
child: TextField(
autofocus: true,
maxLengthEnforced: true,
inputFormatters: <TextInputFormatter>[
LengthLimitingTextInputFormatter(200)
],
controller: editingController,
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.only(
left: 10, right: 10, top: 5, bottom: 5),
border: InputBorder.none,
hintStyle: TextStyle(color: Color(0xffcccccc)),
hintText: "说点什么吧"),
),
),
),
GestureDetector(
onTap: (() {
var text = editingController.text?.trim() ?? "";
if (text.isNotEmpty) {
Navigator.pop(context, text);
}
}),
child: Container(
padding: EdgeInsets.only(
left: 10, right: 10, top: 10, bottom: 10),
alignment: Alignment.center,
child: Text(
"发送",
style: TextStyle(color: Color(0xff00BBBB)),
),
),
)
],
),
),
),
],
),
),
);
}
}
Android中要特别注意 windowSoftInputMode 为 "adjustResize",才能触发键盘引起的bottomInset变化
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">