本文按照由裏到外,從簡單開始一步步向外的順序。完整代碼在最後一段,處理Textfield與showModalBottomSheet衝突致使鍵盤遮擋的bug 的代碼在倒數第二段
要實現的動畫效果html
須要用到以下的 widget / attribute / methodapi
bottomNavigationBar
showModalBottomSheet
AnimatedPadding
TextField
複製代碼
Row textField() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Expanded(
child: new TextField(
decoration: InputDecoration(
hintText: 'Say something here...', //提示文字
border: null,
focusedBorder: UnderlineInputBorder( //輸入框被選中時的邊框樣式
borderSide: BorderSide(color: Colors.blue[300]),
),
),
keyboardType: TextInputType.text, //鍵盤的類型
maxLength: 250, //最多字數
maxLines: 10, //最高行數
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
}複製代碼
首先要使輸入框和發佈按鈕在一行,用Row組件將Textfield & IconButton包裹起來bash
IconButton 的onPressed方法中 Navigator.of(context).pop(); 使得在點擊發送按鈕後,能夠自動關閉頁面app
適當調整樣式less
showModalBottomSheet是從屏幕下方彈出的一個不佔用屏幕所有空間的小頁面,在顯示時屏幕背景會變暗
ide
showModalBottomSheet(
context: context,
builder: (BuildContext context){
return Container(
child: textField(),
padding: EdgeInsets.all(7), //在textField()的全部方向加7單位的邊距(空白)
);
}
);複製代碼
此時用了一個Container包裹Textfield目的是爲了加邊距(固然也有其餘的選擇)測試
底部評論按鈕,要置底,不能隨着頁面的滑動串位。這時可能考慮到用絕對定位,不過有更好的選擇:bottomNavigationBar動畫
在Scaffold中提供了bottomNavigationBar屬性,該屬性提供了:ui
BottomNavigationBar用於底部導航欄,BottomAppBar用於底部應用欄spa
BottomAppBar能夠自定義,因此使用它放置底部評論按鈕
bottomNavigationBar: BottomAppBar(
child: bottomNewCommentButton(),
),複製代碼
代碼很簡單,一目瞭然
下面構造評論按鈕
Container bottomNewCommentButton(){
return Container(
child: RaisedButton(
child: Text("Publish", style: TextStyle(fontSize: 20.0, color: Colors.white)),
color: Colors.blue[300],
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context){
return Container(
child: textField(),
padding: EdgeInsets.all(7),
);
}
);
},
),
height: 50,
);
}複製代碼
在onPressed中放入剛纔寫好的showModalBottomSheet這樣點擊的時候bottomsheet就會顯示出來
寫到這裏應該就會發現Textfield在bottomsheet中的問題:鍵盤會遮擋bottomsheet
通過測試後發現,添加Textfield焦點是法解決問題的
解決方法:
showModalBottomSheet(
context: context,
builder: (BuildContext context){
return new AnimatedPadding(
padding: MediaQuery.of(context).viewInsets, //邊距(必要)
duration: const Duration(milliseconds: 100), //時常 (必要)
child: Container(
child: textField(),
padding: EdgeInsets.all(7),
),
);
}
);複製代碼
在showModalBottomSheet中,原有的Textfield組件外嵌套AnimatedPadding,AnimatedPadding實際上是縮進變化時的動畫,padding和duration是它的必要屬性,缺失會報錯 。
AnimatedPadding api: api.flutter.dev/flutter/wid…
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'showModalBottomSheet',
home: BasicPage(),
);
}
}
class BasicPage extends StatefulWidget {
@override
_BasicPageState createState() => _BasicPageState();
}
class _BasicPageState extends State<BasicPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("showModalBottomSheet"),
),
body: Center(
),
bottomNavigationBar: BottomAppBar(
child: bottomNewCommentButton(),
),
);
}
Container bottomNewCommentButton(){
return Container(
child: RaisedButton(
child: Text("Publish", style: TextStyle(fontSize: 20.0, color: Colors.white)),
color: Colors.blue[300],
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context){
return new AnimatedPadding(
padding: MediaQuery.of(context).viewInsets,
duration: const Duration(milliseconds: 100),
child: Container(
child: textField(),
padding: EdgeInsets.all(7),
),
);
}
);
},
),
height: 50,
);
}
Row textField() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Expanded(
child: new TextField(
decoration: InputDecoration(
hintText: 'Say something here...',
border: null,
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue[300]),
),
),
keyboardType: TextInputType.text,
maxLength: 250,
maxLines: 10,
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
}
}複製代碼