美文网首页
《Flutter实战》第六章

《Flutter实战》第六章

作者: 番茄tomato | 来源:发表于2020-05-11 15:03 被阅读0次
  • 本篇参考资料《Flutter实战》
  • 本篇文章只是本人看书的理解和整理的笔记,更完整的内容还在书上!
  • 电子书链接:https://book.flutterchina.club/
  • Flutter中文社区链接:https://flutterchina.club/
  • 尊重原作者,能支持购买实体书当然最好

本章讲解了ListView等各种可滚动控件的使用,本人根据本章内容完成了一个小demo
效果图如下:


效果图

完整代码仅286行:

import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';

//滚动列表的学习
class MyScrollPage extends StatefulWidget {
  @override
  _MyScrollPageState createState() => _MyScrollPageState();
}

class _MyScrollPageState extends State<MyScrollPage> {
  final pages = [MyListView(), MyGridView(), MyCustomScrollView()];
  final List<BottomNavigationBarItem> bottomNavItems = [
    BottomNavigationBarItem(
      backgroundColor: Colors.blue,
      icon: Icon(Icons.list),
      title: Text("ListView"),
    ),
    BottomNavigationBarItem(
      backgroundColor: Colors.green,
      icon: Icon(Icons.apps),
      title: Text("GridView"),
    ),
    BottomNavigationBarItem(
      backgroundColor: Colors.amber,
      icon: Icon(Icons.label_outline),
      title: Text("CustomScroll"),
    ),
  ];

  int _currentIndex;

  @override
  void initState() {
    super.initState();
    _currentIndex = 0;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        items: bottomNavItems,
        type: BottomNavigationBarType.fixed,
        currentIndex: _currentIndex,
        fixedColor: Colors.blue[300],
        onTap: (index) {
          _changePage(index);
        },
      ),
      body: pages[_currentIndex],
    );
  }

  /*切换页面*/
  void _changePage(int index) {
    /*如果点击的导航项不是当前项  切换 */
    if (index != _currentIndex) {
      setState(() {
        _currentIndex = index;
      });
    }
  }
}

//tab 1
class MyListView extends StatefulWidget {
  @override
  _MyListViewState createState() => _MyListViewState();
}

class _MyListViewState extends State<MyListView> {
  static const loadingTag = "##loading##"; //表尾标记
  var _words = <String>[loadingTag];

  ScrollController _controller = ScrollController();

  bool showToTopBtn = false; //是否显示“返回到顶部”按钮

  @override
  void initState() {
    super.initState();
    _retrieveData();
    _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("ListView"),
      ),
      body: Column(
        children: <Widget>[
          ListTile(title: Text("商品列表")),
          Divider(
            color: Colors.blue,
          ),
          Expanded(
            child: _buildListView(),
          ),
        ],
      ),
      floatingActionButton: !showToTopBtn
          ? null
          : FloatingActionButton(
              child: Icon(Icons.arrow_upward),
              onPressed: () {
                //返回到顶部时执行动画
                _controller.animateTo(.0,
                    duration: Duration(milliseconds: 200), curve: Curves.ease);
              },
            ),
    );
  }

  void _retrieveData() {
    Future.delayed(Duration(seconds: 2)).then((e) {
      setState(() {
        //重新构建列表
        _words.insertAll(
            _words.length - 1,
            //每次生成20个单词
            generateWordPairs().take(20).map((e) => e.asPascalCase).toList());
      });
    });
  }

  Widget _buildListView() {
    return ListView.separated(
        controller: _controller,
        itemCount: _words.length,
        separatorBuilder: (BuildContext context, int index) {
          return index % 2 == 0
              ? Divider(
                  color: Colors.blue,
                )
              : Divider(
                  color: Colors.red,
                );
        },
        itemBuilder: (BuildContext context, int index) {
          if (_words[index] == loadingTag) {
            //不足100条,继续获取数据
            if (_words.length - 1 < 100) {
              _retrieveData();
              //加载时显示loading
              return Container(
                padding: const EdgeInsets.all(16.0),
                alignment: Alignment.center,
                child: SizedBox(
                    width: 24.0,
                    height: 24.0,
                    child: CircularProgressIndicator(strokeWidth: 2.0)),
              );
            } else {
              //已经加载了100条数据,不再获取数据。
              return Container(
                  alignment: Alignment.center,
                  padding: EdgeInsets.all(16.0),
                  child: Text(
                    "没有更多了",
                    style: TextStyle(color: Colors.grey[100]),
                  ));
            }
          }

          return ListTile(
            title: Text(_words[index]),
          );
        });
  }
}

//tab 2
class MyGridView extends StatefulWidget {
  @override
  _MyGridViewState createState() => _MyGridViewState();
}

class _MyGridViewState extends State<MyGridView> {
  @override
  Widget build(BuildContext context) {
    return GridView.extent(
        maxCrossAxisExtent: 300, //横轴三个子widget
        childAspectRatio: 1.0, //宽高
        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)
        ]);
  }
}

//tab 3
class MyCustomScrollView extends StatefulWidget {
  @override
  _MyCustomScrollViewState createState() => _MyCustomScrollViewState();
}

class _MyCustomScrollViewState extends State<MyCustomScrollView> {
  @override
  Widget build(BuildContext context) {
    //因为本路由没有使用Scaffold,为了让子级Widget(如Text)使用
    //Material Design 默认的样式风格,我们使用Material作为本路由的根。
    return Material(
      child: CustomScrollView(
        slivers: <Widget>[
          //AppBar,包含一个导航栏
          SliverAppBar(
            pinned: true,
            expandedHeight: 150.0,
            flexibleSpace: FlexibleSpaceBar(
              title: Text(
                'Demo',
                style: TextStyle(color: Colors.blue[100]),
              ),
              background: Image.asset(
                "assets/images/demo_pic1.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个列表项
                ),
          ),
        ],
      ),
    );
  }
}

相关文章

网友评论

      本文标题:《Flutter实战》第六章

      本文链接:https://www.haomeiwen.com/subject/btpunhtx.html