Flutter学习(八)滚动Widget

2020-04-16  本文已影响0人  yanhooIT

ListView

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("ListView"),
        ),
        body: HomeView(),
      ),
    );
  }
}

class HomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListViewDemo3();
  }
}

class ListViewDemo3 extends StatelessWidget {
  const ListViewDemo3({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    /** ListView.separated
     *
     *  根据子元素的布局父组件会自适应高度
     */
    return ListView.separated(
      itemCount: 100,
      itemBuilder: (BuildContext ctx, int index) {
        return Text(
          "Hello World: $index",
          style: TextStyle(fontSize: 20),
        );
      },
      // 构建分割Widget
      separatorBuilder: (BuildContext ctx, int index) {
        // 分隔线
        return Divider(
          color: Colors.red,
          // 设置Divider的高度
          height: 30,
          // 设置距起始位置的距离
          indent: 10,
          // 设置距结尾位置的距离
          endIndent: 10,
          // 设置线高
          thickness: 2,
        );
      },
    );
  }
}

class ListViewDemo2 extends StatelessWidget {
  const ListViewDemo2({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    /** ListView.builder(这个比较常用)
     *
     *  适合动态创建子元素
     */
    return ListView.builder(
      // 要创建多少个子元素
      itemCount: 100,
      // 设置固定高度
      itemExtent: 60,
      // 当即将显示到屏幕上时才开始构建
      itemBuilder: (BuildContext ctx, int index) {
        return Text(
          "Hello World: $index",
          style: TextStyle(fontSize: 20),
        );
      },
    );
  }
}

class ListViewDemo1 extends StatelessWidget {
  const ListViewDemo1({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView(
      // 设置滚动方向
//      scrollDirection: Axis.horizontal,
      // 显示反转
//      reverse: true,
      // 设置子组件的固定高度
      // 当设置scrollDirection: Axis.horizontal,须指定每一个item的固定宽度
      itemExtent: 80,
      /**  ListView.generate批量创建ListView的子元素
       *
       * (1)只适合子元素比较少的场景,如果元素比较多就会比较耗费内存
       * (2)动态不固定的的子元素不建议用此方法,建议用List.builder替代
       */
      children: List.generate(100, (index) {
        return ListTile(
          // 左边显示的组件
          leading: Icon(Icons.people),
          // 右边显示的组件
          trailing: Icon(Icons.delete),
          // 主标题
          title: Text("联系人${index + 1}"),
          // 子标题
          subtitle: Text("联系人电话号码:18866665555"),
        );
      }),
    );
  }
}

GridView

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("GridView"),
        ),
        body: HomeView(),
      ),
    );
  }
}

class HomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GridViewDemo3();
  }
}

class GridViewDemo3 extends StatelessWidget {
  const GridViewDemo3({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    /// 这种方式在开发中比较常用
    return GridView.builder(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          // 每一行固定显示几个
            crossAxisCount: 3,
            // 宽高比,即:这个比率 = 宽度 / 高度,可以根据这个值来确定子元素的高度
            childAspectRatio: 2,
            // 交叉轴每个子元素之间的间距
            crossAxisSpacing: 8,
            // 主轴每个子元素之间的间距
            mainAxisSpacing: 20
        ),
        itemBuilder: (BuildContext ctx, int index) {
          return Container(
            color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256), Random().nextInt(256)),
          );
        }
    );
  }
}

class GridViewDemo2 extends StatelessWidget {
  const GridViewDemo2({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GridView(
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        // 设置固定宽度
        maxCrossAxisExtent: 400,
        // 宽高比,即:这个比率 = 宽度 / 高度,可以根据这个值来确定子元素的高度
        childAspectRatio: 2,
        crossAxisSpacing: 8,
        mainAxisSpacing: 20,
      ),
      children: List.generate(100, (index) {
        return Container(
          color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256), Random().nextInt(256)),
        );
      }),
    );
  }
}

class GridViewDemo1 extends StatelessWidget {
  const GridViewDemo1({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GridView(
      // 固定子元素个数
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        // 每一行固定显示几个
          crossAxisCount: 3,
          // 宽高比,即:这个比率 = 宽度 / 高度,可以根据这个值来确定子元素的高度
          childAspectRatio: 2,
          // 交叉轴每个子元素之间的间距
          crossAxisSpacing: 8,
          // 主轴每个子元素之间的间距
          mainAxisSpacing: 20
      ),
      children: List.generate(100, (index) {
        return Container(
          color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256), Random().nextInt(256)),
        );
      }),
    );
  }
}

CustomScrollView

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
//        appBar: AppBar(
//          title: Text("CustomScrollView"),
//        ),
        body: HomeView(),
      ),
    );
  }
}

class HomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CustomScrollView2();
  }
}

class CustomScrollView2 extends StatelessWidget {
  const CustomScrollView2({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: <Widget>[
        // 属于滚动条的导航栏
        SliverAppBar(
          // 固定导航栏
          pinned: true,
          // 设置导航栏的扩展区域高度
          expandedHeight: 200,
          // 设置在扩展区域要显示的内容
          flexibleSpace: FlexibleSpaceBar(
            title: Container(
                color: Colors.black,
                child: Text("Hello World", style: TextStyle(color: Colors.white, fontSize: 20),)),
            // BoxFit.cover:会按图片的长宽比放大后居中填满显示空间,图片不会变形,超出显示空间部分会被剪裁
            background: Image.asset("assets/images/xuebao.png", fit: BoxFit.cover),
          ),
        ),
        // 类似GridView
        SliverGrid(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              crossAxisSpacing: 8,
              mainAxisSpacing: 8,
              childAspectRatio: 2
          ),
          delegate: SliverChildBuilderDelegate(
                  (BuildContext ctx, int int) {
                return Container(color: Color.fromARGB(255, Random().nextInt(
                    256), Random().nextInt(256), Random().nextInt(256)));
              },
              // 显示四个元素
              childCount: 4
          ),
        ),
        // 类似ListView
        SliverList(
          delegate: SliverChildBuilderDelegate(
                  (BuildContext ctx, int index) {
                return ListTile(
                  leading: Icon(Icons.people),
                  title: Text("联系人$index"),
                );
              },
              childCount: 20
          ),
        )
      ],
    );
  }
}

class CustomScrollView1 extends StatelessWidget {
  const CustomScrollView1({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    /// 可以统一管理多个滚动视图
    /// 在CustomScrollView中,每一个独立的,可滚动的Widget被称之为Sliver
    return CustomScrollView(
      slivers: <Widget>[
        // 设置安全区域,只在安全区域里显示,类似的还有SafeArea
        SliverSafeArea(
          // 设置内间距
          sliver: SliverPadding(
            padding: EdgeInsets.all(8),
            /// SliverGrid类似于我们之前使用过的GridView
            sliver: SliverGrid(
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2,
                  crossAxisSpacing: 8,
                  mainAxisSpacing: 8,
                  childAspectRatio: 1.5
              ),
              // 设置代理,之前的generate、builder方法分别对应SliverChildListDelegate、SliverChildBuilderDelegate
              delegate: SliverChildBuilderDelegate(
                      (BuildContext ctx, int int) {
                    return Container(color: Color.fromARGB(255, Random().nextInt(
                        256), Random().nextInt(256), Random().nextInt(256)));
                  },
                  // 一共有多少个元素,不设置就是无限个
                  childCount: 20
              ),
            ),
          ),
        )
      ],
    );
  }
}

事件监听

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '监听滚动事件',
      theme: ThemeData(
          primarySwatch: Colors.blue, splashColor: Colors.transparent),
      home: HomeView(),
    );
  }
}

class HomeView extends StatefulWidget {
  @override
  _HomeViewState createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView> {
  // 可以指定初始的偏移量,这里直接设置为0,没有初始偏移量
  ScrollController _controller = ScrollController(initialScrollOffset: 0);
  bool _isShowFloatingBtn = false;

  @override
  void initState() {
    super.initState();

    _controller.addListener(() {
      print("监听到滚动....: ${_controller.offset}");

      setState(() {
        _isShowFloatingBtn = _controller.offset >= 300;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    /**
     * 两种方式可以监听:
     *
     *  1、controller:
     *    可以设置默认值offset
     *    监听滚动, 也可以监听滚动的位置
     *
     *  2、NotificationListener
     *    开始滚动 和 结束滚动
     */
    return Scaffold(
      appBar: AppBar(
        title: Text("监听滚动事件"),
      ),
      body: NotificationListener(
        onNotification: (ScrollNotification notification) {
          if (notification is ScrollStartNotification) {
            print("开始滚动,可滚动距离:${notification.metrics.maxScrollExtent}");
          } else if (notification is ScrollUpdateNotification) {
            print(
                "正在滚动... 当前滚动的位置: ${notification.metrics.pixels}");
          } else if (notification is ScrollEndNotification) {
            print("结束滚动");
          }

          // 返回一个布尔值,代表是否阻止该事件继续向上冒
          // 如果为true时,则冒泡终止,事件停止向上传播
          // 如果不返回 或者 返回值为false时,则冒泡继续
          return true;
        },
        child: ListView.builder(
            controller: _controller,
            itemCount: 30,
            itemBuilder: (BuildContext ctx, int index) {
              return ListTile(
                leading: Icon(Icons.people),
                title: Text("联系人$index"),
              );
            }),
      ),
      floatingActionButton: _isShowFloatingBtn
          ? FloatingActionButton(
        child: Icon(Icons.arrow_upward),
        onPressed: () {
          // 滚动到顶部
          // jumpTo没有动画效果
//                _controller.jumpTo(0);

          // animateTo是带动画效果的
          _controller.animateTo(0, duration: Duration(seconds: 1), curve: Curves.easeIn);
        },
      )
          : null,
    );
  }

  @override
  void dispose() {
    super.dispose();

    _controller.dispose();
  }
}
上一篇下一篇

猜你喜欢

热点阅读