前言
在日常開發(fā)中我們可能會遇到這種設(shè)計,上半部分的內(nèi)容是固定的,然后中間是空白,下面是按鈕,當屏幕空間顯示不下的時候,就壓縮空白區(qū)域,如果空白區(qū)域被壓縮完了,就整體滾動(或者上半部分滾動)。
布局
根據(jù)上面的示意圖,隨意創(chuàng)建幾個Widget出來,效果如下
class AutoResizeSpacer extends StatelessWidget {
const AutoResizeSpacer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('自動壓縮空白區(qū)域 '),
),
body: Column(
children: [
_textField('請輸入賬號(手機/郵箱)'),
_textField('請輸入驗證碼'),
_textField('請輸入密碼'),
_button(),
],
),
);
}
Widget _textField(String labelText) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(labelText: labelText),
),
);
}
Widget _button() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(onPressed: () {}, child: const Text('我是按鈕')),
);
}
}
上面的代碼就把布局給做出來了,但是是不符合設(shè)計要求的效果的,接下來就是完成設(shè)計的效果。
在Flutter里面,空白可以用Spacer來表示,這個小部件會撐滿剩余的空間,所以我們就可以在Column中新增一個Spacer。效果如下
Column(
children: [
...
const Spacer(),
...
]
)
上面這個報錯,對于Flutter開發(fā)來說那不是家常便飯,解決起來也和喝水一樣簡單,你可能馬上就會想到SingleChildScrollView包裹起來,然后。。。你就會發(fā)現(xiàn)啥都沒有了
這個也很好理解,就是Spacer惹的禍。
方案一:底部固定,上半部分滾動
對于上面那種情況,我們可以在外層在套用一個Column,同時把Button提到外面這個Column中,就可以完成這個設(shè)計
...
body:Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
_textField('請輸入賬號(手機/郵箱)'),
_textField('請輸入驗證碼'),
_textField('請輸入密碼'),
],
),
),
),
_button(),
],
),
...
這個很好理解,把Column分為兩個部分,一個是擴展區(qū)域,另外一個是按鈕的空間,擴展區(qū)域(上半部分)在用一個SIngleChildScrollView進行包裹,當空間不夠展示完整的child的時候,就可以滾動。
方案二:整體滾動
可以使用CustomScrollView,在配合SliverFillRemaining來完成。
使用之前先來了解一下SliverFillRemaining這個widget,點進去看到他的官方說明:A sliver that contains a single box child that fills the remaining space in the viewport.
,會填充一整屏(一整個viewport)的空間,可以用下面的gif來理解
SliverFillRemaining里面有一個屬性是:hasScrollBody,意思就是要不要動態(tài)計算最大可用范圍,默認是開啟的。我們把它關(guān)閉,然后再觀察一下下面這個gif
到這里應(yīng)該就知道如何處理了,把button放在SliverFillRemaining中,然后調(diào)整一下他的布局方式就可以完成上面的效果
...
body: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Column(
children: [
_textField('請輸入賬號(手機/郵箱)'),
_textField('請輸入驗證碼'),
_textField('請輸入密碼'),
],
),
),
SliverFillRemaining(
hasScrollBody: false,
child: Align(
alignment: Alignment.bottomCenter,
child: _button(),
),
),
],
)
...
結(jié)尾
到這里就可以根據(jù)要求完成上面的效果了,由于代碼量很少,就不上傳git了,貼一下全部代碼吧
class AutoResizeSpacer extends StatelessWidget {
const AutoResizeSpacer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('自動壓縮空白區(qū)域 '),
),
body: _body2(),
);
}
Widget _body2() {
return CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Column(
children: [
_textField('請輸入賬號(手機/郵箱)'),
_textField('請輸入驗證碼'),
_textField('請輸入密碼'),
],
),
),
SliverFillRemaining(
hasScrollBody: false,
child: Align(
alignment: Alignment.bottomCenter,
child: _button(),
),
),
],
);
}
Widget _body1() {
return Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
_textField('請輸入賬號(手機/郵箱)'),
_textField('請輸入驗證碼'),
_textField('請輸入密碼'),
],
),
),
),
_button(),
],
);
}
Widget _textField(String labelText) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
decoration: InputDecoration(labelText: labelText),
),
);
}
Widget _button() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(onPressed: () {}, child: const Text('我是按鈕')),
);
}
}