【原創不易,轉載請註明出處:https://blog.csdn.net/email_jade/article/details/87915598】
今天給大家帶來的是一個非常常見的佈局,通過GridView和PageView實現類似於聊天表情emoji佈局的功能,我們先來看一下效果吧:
看了標題大家應該清楚,組成該佈局的主體元素是GridView和PageView。
我們來分解一下佈局,佈局見上下兩部分,上面的圖標和下面的頁指示器,頁指示器比較簡單,一個居中的Row佈局搞定,如下,其中_pageCount代表總頁數:
///頁標
Widget _buildCursor() {
List<Widget> list = List();
for (int i = 0; i < _pageCount; i++) {
list.add(_buildPoint(_currentPage == i));
}
return Container(
child: Row(
children: list,
mainAxisSize: MainAxisSize.min,
),
alignment: AlignmentDirectional.center,
);
}
///單個點
Widget _buildPoint(bool focus) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Container(
width: 10, height: 10, color: focus ? Colors.black : Colors.grey),
);
}
圖標部分,單頁可以看做是一個GridView,而多個GridView又組成了一個PageView,由於翻頁的時候要聯動下面的頁指示器跟着改變,因此要使用到PageView的PageController動態改變頁數,代碼如下,要記得及時釋放controller:
final List<Widget> children;
final int column; //列數
final int row; //行數
final double columnSpacing; //列間隔
final double rowSpacing; //行間隔
final double itemRatio; //每個item的寬高比,默認正方形
。。。。
///每頁的個數
int _countPerPage;
///總頁數
int _pageCount;
///當前頁
int _currentPage;
///控制器
PageController _controller;
///計算總頁數及單頁的item數目
void _calculatePage() {
assert(widget.children != null);
_countPerPage = widget.row * widget.column;
_pageCount = (widget.children.length / _countPerPage).ceil();
}
///多個Item構建單頁的GridView
Widget _buildGrid(List<Widget> list) {
return GridView.count(
crossAxisCount: widget.column,
children: list,
mainAxisSpacing: widget.rowSpacing,
crossAxisSpacing: widget.columnSpacing,
childAspectRatio: widget.itemRatio,
);
}
///構建多個GridView
List<Widget> _buildPages() {
List<Widget> list = List();
int index = 0;
int realIndex;
for (int i = 0; i < _pageCount; i++) {
realIndex = index + _countPerPage > widget.children.length
? widget.children.length
: index + _countPerPage;
List l = widget.children.sublist(index, realIndex);
index = realIndex;
list.add(_buildGrid(l));
}
return list;
}
///多個GridView構建PageView
Widget _buildPageView() {
return PageView(
controller: _controller,
children: _buildPages(),
onPageChanged: (page) {
setState(() {
_currentPage = page;
});
},
);
}
佈局已經完成,比較簡單。當然,其實有很多內容可以擴展,比如可以通過Container的BoxDecoration shape屬性shape: BoxShape.circle改變頁指示器爲圓形,也可以通過修改item動態改變樣式,比如說是圖片和標題組成的Item,等等,都由實際情況來決定,只要大體結構不變,就可以使用此模塊。
下面是使用部分,演示的時候用到了fluttertoast控件:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: GridPage(children: _buildChildren(), column: 7, row: 4,),
);
}
///構建數據
List<Widget> _buildChildren(){
List<Widget> list = List();
for(int i=0; i<133; i++){
list.add(GestureDetector(child:Icon(Icons.android, color: Colors.green, size: 40.0,), onTap: (){
Fluttertoast.showToast(msg: "item $i on click");
},),);
}
return list;
}
}
完整代碼見:
https://github.com/jadennn/flutter_grid_page
flutter很好,路還很長,讓我們一起奮鬥前行!