如果元件實際尺寸超出可用空間,解決的方式之一是使用 SingleChildScrollView
,例如在〈使用輸入欄位〉中,就使用了 SingleChildScrollView
,避免鍵盤出現時因可用空間縮小,而造成輸入欄位無法繪製完全,而出現黃黑斑紋條。
SingleChildScrollView
顧名思義,只能指定一個子元件,通常這是在你的子元件內容固定,或者是子元件中清單之類的元件數量不多時使用,因為 SingleChildScrollView
沒有延遲載入的效果,如果子元件清單之類的元件數量很多,或者是隨時需要動態載入,SingleChildScrollView
就不適合(這時可考慮 ListView
之類的其他元件)。
SingleChildScrollView
只能指定一個子元件,如果這個子元件中需要清單之類的元件,雖然可以用 Column
、Row
之類的來組合,不過使用 ListBody
會更方便,例如〈使用輸入欄位〉中的例子,也可以使用 ListBody
改寫如下:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Openhome.cc')),
body: Login(),
)
)
);
class Login extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Login();
}
class _Login extends State<Login> {
final nameController = TextEditingController();
final passwdController = TextEditingController();
@override
void dispose() {
nameController.dispose();
passwdController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView( // SingleChildScrollView
child: ListBody( // 搭配 ListBody
children: [
TextField(
decoration: InputDecoration(
labelText: '帳號',
hintText: '使用者名稱或郵件',
prefixIcon: Icon(Icons.person)
),
controller: nameController,
),
TextField(
decoration: InputDecoration(
labelText: '密碼',
prefixIcon: Icon(Icons.lock),
),
obscureText: true,
controller: passwdController,
),
FlatButton(
child: Text('登入'),
onPressed: () {
print('名稱:${nameController.text}');
print('密碼:${passwdController.text}');
},
)
]
)
);
}
}
SingleChildScrollView
有一些特性,例如 scrollDirection
、physics
、controller
等,這些特性實際上是給內部的 Scrollable
使用,Flutter 中一些可捲動元件,內部會是由 Scrollable
實際在控制捲動的行為,你不太會自行使用 Scrollable
,因為捲動本身是個很複雜的行為,必須控制事件、版面、繪圖等,基本上只要先知道有 Scrollable
的存在,而內部使用了 Scrollable
的元件,都會有這類可設定的特性就可以了。
例如,可捲動元件的捲動方向,可以是垂直與水平:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Openhome.cc')),
body: Body(),
)
)
);
class Body extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Body();
}
class _Body extends State<Body> {
final scrollController = ScrollController();
@override
void dispose() {
scrollController.dispose(); // 釋放控制器
super.dispose();
}
@override
Widget build(BuildContext context) {
var children = List<Widget>();
for(var i = 0; i < 20; i++) {
children.add(RawMaterialButton(
child: Text('$i'),
onPressed: () {
print(scrollController.offset); // 取得捲動偏移值
},
fillColor: Colors.lightGreen,
splashColor: Colors.red,
));
}
return SingleChildScrollView(
controller: scrollController,
scrollDirection: Axis.horizontal, // 水平捲動
child: Center(
child: Container(
height: 50,
child: ListBody(
mainAxis: Axis.horizontal, // 水平排列
children: children
)
),
)
);
}
}
範例中也示範了如何使用 ScrollController
,以取得捲動偏移值,基本上與〈使用輸入欄位〉中控制器的使用方式類似,執行後效果如下: