列表是APP的核心功能,目前這個庫不算完善,之後國外的大神應該會補全,如今的樣式就是很基礎的東西,解決一些經常使用的加載,至於後面的自定義tag須要一個過程,混合佈局能夠參考flutter_staggered_grid_view,下面是基礎的寫法:
java
import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); //Stateless widgets 是不可變的, 這意味着它們的屬性不能改變 - 全部的值都是最終的. //Stateful widgets 持有的狀態可能在widget生命週期中發生變化. 實現一個 stateful widget 至少須要兩個類: class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // final wordPair = new WordPair.random(); return new MaterialApp( title: 'ListView3+GridView33', debugShowCheckedModeBanner: false, theme: new ThemeData( primarySwatch: Colors.blue, // fontFamily: 'fontdemo1' ), home: new Scaffold( appBar: new AppBar( title: new Text('圖片加載'), ), body: new Center( // child: new ListView( // shrinkWrap: true, // padding: const EdgeInsets.all(20.0), // children: <Widget>[ // const Text('I\'m dedicating every day to you'), // const Text('Domestic life was never quite my style'), // const Text('When you smile, you knock me out, I fall apart'), // const Text('And I thought I was so smart'), // ], // ), // child: new ListView3(), // child: new GridView3(), // child: new GridView33(), child: new InfiniteGridView(), ), ), ); } } class ListView3 extends StatelessWidget { @override Widget build(BuildContext context) { //下劃線widget預約義以供複用。 Widget divider1 = Divider( color: Colors.blue, ); Widget divider2 = Divider(color: Colors.green); return ListView.separated( itemCount: 100, //列表項構造器 itemBuilder: (BuildContext context, int index) { return ListTile(title: Text("$index")); }, //分割器構造器 separatorBuilder: (BuildContext context, int index) { return index % 2 == 0 ? divider1 : divider2; }, ); } } class GridView3 extends StatelessWidget { @override Widget build(BuildContext context) { return GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, //橫軸三個子widget childAspectRatio: 1.0, //寬高比爲1時,子widget ), children: <Widget>[ Icon(Icons.ac_unit), Icon(Icons.airport_shuttle), Icon(Icons.all_inclusive), Icon(Icons.beach_access), Icon(Icons.cake), Icon(Icons.free_breakfast) ]); } } class GridView33 extends StatelessWidget { @override Widget build(BuildContext context) { return GridView( padding: EdgeInsets.zero, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 120.0, childAspectRatio: 2.0, //寬高比爲2 ), children: <Widget>[ Icon(Icons.ac_unit), Icon(Icons.airport_shuttle), Icon(Icons.all_inclusive), Icon(Icons.beach_access), Icon(Icons.cake), Icon(Icons.free_breakfast), ], ); } } class InfiniteGridView extends StatefulWidget { @override _InfiniteGridViewState createState() => new _InfiniteGridViewState(); } class _InfiniteGridViewState extends State<InfiniteGridView> { List<IconData> _icons = []; //保存Icon數據 @override void initState() { // 初始化數據 _retrieveIcons(); } @override Widget build(BuildContext context) { return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, //每行三列 childAspectRatio: 1.0 //顯示區域寬高相等 ), itemCount: _icons.length, itemBuilder: (context, index) { //若是顯示到最後一個而且Icon總數小於200時繼續獲取數據 if (index == _icons.length - 1 && _icons.length < 200) { _retrieveIcons(); } return Icon(_icons[index]); } ); } //模擬異步獲取數據 void _retrieveIcons() { Future.delayed(Duration(milliseconds: 200)).then((e) { setState(() { _icons.addAll([ Icons.ac_unit, Icons.airport_shuttle, Icons.all_inclusive, Icons.beach_access, Icons.cake, Icons.free_breakfast ]); }); }); } }
ListView+GridView圖文混合:
網絡
import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); //Stateless widgets 是不可變的, 這意味着它們的屬性不能改變 - 全部的值都是最終的. //Stateful widgets 持有的狀態可能在widget生命週期中發生變化. 實現一個 stateful widget 至少須要兩個類: class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // final wordPair = new WordPair.random(); return new MaterialApp( title: 'ListView+GridView綜合佈局', debugShowCheckedModeBanner: false, theme: new ThemeData( primarySwatch: Colors.blue, // fontFamily: 'fontdemo1' ), home: new Scaffold( // appBar: new AppBar( //// title: new Text('圖片加載'), //// ), body: new Center( // child: new ListView( // shrinkWrap: true, // padding: const EdgeInsets.all(20.0), // children: <Widget>[ // const Text('I\'m dedicating every day to you'), // const Text('Domestic life was never quite my style'), // const Text('When you smile, you knock me out, I fall apart'), // const Text('And I thought I was so smart'), // ], // ), // child: new ListView3(), // child: new GridView3(), // child: new GridView33(), child: new CustomScrollViewTestRoute(), ), ), ); } } class CustomScrollViewTestRoute extends StatelessWidget { @override Widget build(BuildContext context) { //由於本路由沒有使用Scaffold,爲了讓子級Widget(如Text)使用 //Material Design 默認的樣式風格,咱們使用Material做爲本路由的根。 return Material( child: CustomScrollView( slivers: <Widget>[ //AppBar,包含一個導航欄 SliverAppBar( //標題居中 centerTitle: true, leading: Builder(builder: (context) { return IconButton( icon: Icon(Icons.arrow_back, color: Colors.white), //自定義圖標 onPressed: () { // }, ); }), // leading: Icon( // Icons.arrow_back, // ), //展開高度250 expandedHeight: 250.0, //不隨着滑動隱藏標題 floating: false, //固定在頂部 pinned: true, flexibleSpace: FlexibleSpaceBar( title: const Text('YUN'), background: Image.asset( "assets/images/food04.jpeg", fit: BoxFit.cover, ), ), ), SliverPadding( padding: const EdgeInsets.all(8.0), sliver: new SliverGrid( //Grid gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, //Grid按兩列顯示 mainAxisSpacing: 10.0, crossAxisSpacing: 10.0, childAspectRatio: 4.0, ), delegate: new SliverChildBuilderDelegate( (BuildContext context, int index) { //建立子widget return new Container( alignment: Alignment.center, color: Colors.cyan[100 * (index % 9)], child: new Text('grid item $index'), ); }, childCount: 20, ), ), ), //List new SliverFixedExtentList( itemExtent: 50.0, delegate: new SliverChildBuilderDelegate( (BuildContext context, int index) { //建立列表項 return new Container( alignment: Alignment.center, color: Colors.lightBlue[100 * (index % 9)], child: new Text('list item $index'), ); }, childCount: 50 //50個列表項 ), ), ], ), ); } }
滾動監聽及控制:
app
import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); //Stateless widgets 是不可變的, 這意味着它們的屬性不能改變 - 全部的值都是最終的. //Stateful widgets 持有的狀態可能在widget生命週期中發生變化. 實現一個 stateful widget 至少須要兩個類: class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // final wordPair = new WordPair.random(); return new MaterialApp( title: '滾動監聽及控制', debugShowCheckedModeBanner: false, theme: new ThemeData( primarySwatch: Colors.blue, // fontFamily: 'fontdemo1' ), home: new Scaffold( appBar: new AppBar( title: new Text('滾動監聽及控制'), ), body: new Center( // child: new ListView( // shrinkWrap: true, // padding: const EdgeInsets.all(20.0), // children: <Widget>[ // const Text('I\'m dedicating every day to you'), // const Text('Domestic life was never quite my style'), // const Text('When you smile, you knock me out, I fall apart'), // const Text('And I thought I was so smart'), // ], // ), // child: new ListView3(), // child: new GridView3(), // child: new GridView33(), child: new ScrollControllerTestRoute(), // child: new ScrollNotificationTestRoute(), ), ), ); } } class ScrollControllerTestRoute extends StatefulWidget { @override ScrollControllerTestRouteState createState() { return new ScrollControllerTestRouteState(); } } class ScrollControllerTestRouteState extends State<ScrollControllerTestRoute> { ScrollController _controller = new ScrollController(); bool showToTopBtn = false; //是否顯示「返回到頂部」按鈕 @override void initState() { //監聽滾動事件,打印滾動位置 _controller.addListener(() { print(_controller.offset); //打印滾動位置 if (_controller.offset < 1000 && showToTopBtn) { setState(() { showToTopBtn = false; }); } else if (_controller.offset >= 1000 && showToTopBtn == false) { setState(() { showToTopBtn = true; }); } }); } @override void dispose() { //爲了不內存泄露,須要調用_controller.dispose _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( // appBar: AppBar(title: Text("滾動控制")), body: Scrollbar( child: ListView.builder( itemCount: 100, itemExtent: 50.0, //列表項高度固定時,顯式指定高度是一個好習慣(性能消耗小) controller: _controller, itemBuilder: (context, index) { return ListTile( title: Text("$index"), ); }), ), floatingActionButton: !showToTopBtn ? null : FloatingActionButton( child: Icon(Icons.arrow_upward), onPressed: () { //返回到頂部時執行動畫 _controller.animateTo(.0, duration: Duration(milliseconds: 200), curve: Curves.ease); }), ); } } class ScrollNotificationTestRoute extends StatefulWidget { @override _ScrollNotificationTestRouteState createState() => new _ScrollNotificationTestRouteState(); } class _ScrollNotificationTestRouteState extends State<ScrollNotificationTestRoute> { String _progress = "0%"; //保存進度百分比 @override Widget build(BuildContext context) { return Scrollbar( //進度條 // 監聽滾動通知 child: NotificationListener<ScrollNotification>( onNotification: (ScrollNotification notification) { double progress = notification.metrics.pixels / notification.metrics.maxScrollExtent; //從新構建 setState(() { _progress = "${(progress * 100).toInt()}%"; }); print("BottomEdge: ${notification.metrics.extentAfter == 0}"); //return true; //放開此行註釋後,進度條將失效 }, child: Stack( alignment: Alignment.center, children: <Widget>[ ListView.builder( itemCount: 100, itemExtent: 50.0, itemBuilder: (context, index) { return ListTile(title: Text("$index")); }), CircleAvatar( //顯示進度百分比 radius: 30.0, child: Text(_progress), backgroundColor: Colors.black54, ) ], ), ), ); } }
總結:學完網絡請求,你們把tolist裏面改寫就能夠獨立出來不一樣的樣式去加載數據,仍是挺方便的,代碼精簡很多~加油~
less