如果想去掉widget預設的padding,需要用MediaQuery.removePadding包裹
MediaQuery.removePadding(context: context,
removeTop: true,
child:widget)
基于ExpansionTile實作可展開的清單,相等于Android中的ExpandableListView
class SearchPage extends StatefulWidget{
@override
State<StatefulWidget> createState() => _SearchState();
}
class _SearchState extends State<SearchPage>{
var map = {
"北京":["東城區","西城區","朝陽區","海澱區","豐台區"],
"上海":["浦東區","虹口區","靜安寺區"],
"山東":["濟南","青島","濰坊","煙台","聊城"]
};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("搜尋"),),
body: ListView(
children: _buildCity()
)
);
}
List<Widget> _buildCity(){
List<Widget> widgets = [];
map.keys.forEach((key){
widgets.add(_buildSubCity(map[key],key));
});
return widgets;
}
Widget _buildSubCity(List<String> subCities,String city){
return ExpansionTile(
title: Text(city),
initiallyExpanded:false,
children: subCities.map((title)=>_buildItem(title)).toList()
);
}
Widget _buildItem(String title){
return FractionallySizedBox(
widthFactor: 1,
child: Container(
height: 50,
alignment: Alignment.centerLeft,
child: Text(title),
color: Colors.lightBlue,
margin: EdgeInsets.only(top: 5),
),
);
}
}
基于GridView實作網格清單
class TravelPage extends StatefulWidget{
@override
State<StatefulWidget> createState() => _TravelState();
}
const CITY_NAMES = ['北京','上海','廣州','深圳','杭州','蘇州','天津','重慶','青島','煙台','大連','哈爾濱'];
class _TravelState extends State<TravelPage>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("旅拍"),),
body: GridView.count(
crossAxisCount: 2,
children: _buildItems(),
)
);
}
List<Widget> _buildItems(){
List<Widget> widgets = [];
for(int i = 0 ; i < CITY_NAMES.length; i++){
widgets.add(_buildItem(CITY_NAMES[i],i));
}
return widgets;
}
Widget _buildItem(String city,int position){
return Container(
height: 80,
decoration: BoxDecoration(color: Colors.teal),
margin: EdgeInsets.only(bottom: 5, right: position % 2 == 0 ? 2.5 : 0,left: position % 2 == 0 ? 0 : 2.5),
alignment: Alignment.center,
child: Text(city,
style: TextStyle(color: Colors.white,fontSize: 20),
),
);
}
}
進階功能清單下拉重新整理和上拉加載更多功能的實作
下拉重新整理的實作
1.使用RefreshIndicator包裹ListView
2.實作RefreshIndicator的onRefresh方法
上拉加載更多的實作:
1.為ListView設定一個ScrollController
2.為ScrollController在initState方法中添加一個監聽:ScrollController.addListener((){});
3.在addListener中判斷是否滑動到最下方(ScrollController.positon.pixels == ScrollController.position.maxScrollExtent)如果為true就執行loadMore方法
class MyPage extends StatefulWidget{
@override
State<StatefulWidget> createState() => _MyState();
}
const CITIES = ['北京','上海','廣州','深圳','杭州','蘇州','天津','重慶','青島','煙台','大連','哈爾濱','洛陽','無錫'];
class _MyState extends State<MyPage>{
var cities = List<String>.from(CITIES);
var _scrollController = ScrollController();
@override
void initState() {
super.initState();
_scrollController.addListener((){
print(_scrollController.position);
print(_scrollController.position.pixels);
if(_scrollController.position.pixels == _scrollController.position.maxScrollExtent){
_onLoadMore();
print("on load more");
}
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
Future<Null> _onLoadMore() async{
await Future.delayed(Duration(milliseconds: 500));
setState(() {
cities.add("load more");
});
return null;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("我的"),),
body: RefreshIndicator(child: ListView(
controller: _scrollController,
children: _buildItems(),
), onRefresh: _onRefresh)
);
}
List<Widget> _buildItems(){
return cities.map((city)=>_buildItem(city)).toList();
}
Widget _buildItem(String city) {
return Container(
height: 40,
decoration: BoxDecoration(color: Colors.teal),
margin: EdgeInsets.only(bottom: 5,),
alignment: Alignment.center,
child: Text(city,
style: TextStyle(color: Colors.white, fontSize: 20),
),
);
}
Future<Null> _onRefresh() async{
await Future.delayed(Duration(milliseconds: 2000));
setState(() {
cities = cities.reversed.toList();
});
return null;
}
}