[Flutter Scrollable]-滚动列表


滚动列表与动态加载

ListView

//特点:一次性加载完所有东西,对于列项多的项目非常耗性能
ListView(
    children: [
        Container(
            height: 300,
            width: 300,
            color: Colors.red,
        ),
        Text('nihao flutter'),
        Text('Hello world'),
        Container(
            height: 300,
            width: 300,
            color: Colors.red,
        ),
        Text('Hello world'),
        Container(
            height: 300,
            width: 300,
            color: Colors.red,
        ),
        Text('Hello world'),
        Container(
            height: 300,
            width: 300,
            color: Colors.red,
        ),
        Text('Hello world'),
        Container(
            height: 300,
            width: 300,
            color: Colors.red,
        ),
    ],
),

ListView.builder

ListView.builder(
    itemCount: 100, //条目
    itemExtent: 100, //每一条条目的高度
    cacheExtent: 300, //缓冲区域(预加载)
    itemBuilder: (context, index) {
        return Container(
            height: 100,
            width: double.infinity,
            color: Colors.blue[200],
            alignment: Alignment.center,
            child: Text('$index'));
    },
),

ListView.separated

ListView.separated(
    separatorBuilder: (context, index) {
        return Divider(//分割线
            height: 1,
        );
    },
    itemCount: 100, //条目
    cacheExtent: 300, //缓冲区域(预加载),
    itemBuilder: (context, index) {
        return Container(
            height: 100,
            width: double.infinity,
            color: Colors.blue[200],
            alignment: Alignment.center,
            child: Text('$index'));
    },
)

深入详解ListView组件

//定义controller
//final _controller = ScrollController();

Scrollbar(
    child: ListView.builder(
        //physics: NeverScrollableScrollPhysics(),//不能滚动了
        controller: _controller,//设置控制器
        padding: const EdgeInsets.only(bottom: 140),//底部留有空白
        //scrollDirection: Axis.horizontal,//横竖屏切换
        itemExtent: 60,
        itemCount: 80,
        itemBuilder: (context, index) {
            return ListTile(
                leading: Icon(Icons.person),
                title: Text('Name'),
                subtitle: Text('Introduction'),
                trailing: IconButton(
                    icon: Icon(Icons.delete_outline),
                ),
            );
        },
    ),
),
floatingActionButton: FloatingActionButton(
    onPressed: () {
        //按一次下降200像素
        _controller.animateTo(_controller.offset + 200,
                              duration: Duration(seconds: 2), 
                              curve: Curves.linear);
    },
    child: Icon(Icons.arrow_circle_down_outlined),
),
),

点击标题回到top

AppBar(
    centerTitle: true,
    title: GestureDetector(
        onTap: () {
            _controller.animateTo(
                -20.0,
            	duration: Duration(seconds: 1), 
                curve: Curves.linear);
        },
        child: Text(
            '滚动列表',
        )),
),

下拉刷新与通知事件

RefreshIndicator(
    strokeWidth: 2.0, //指示器宽度
    color: Colors.white, //指示器颜色
    backgroundColor: Colors.black, //背景颜色
    onRefresh: () async {
        await Future.delayed(Duration(seconds: 2));
    },
    child: Scrollbar(
        child: ListView.builder(
            //physics: NeverScrollableScrollPhysics(),//不能滚动了
            controller: _controller,
            padding: const EdgeInsets.only(bottom: 140),
            //scrollDirection: Axis.horizontal,
            itemExtent: 60,
            itemCount: 80,
            itemBuilder: (context, index) {
                return ListTile(
                    leading: Icon(Icons.person),
                    title: Text('Name'),
                    subtitle: Text('Introduction'),
                    trailing: IconButton(
                        icon: Icon(Icons.delete_outline),
                    ),
                );
            },
        ),
    ),
),
NotificationListener(
    //拦截监听
    onNotification: (ScrollNotification _event) {
        print(_event);
        return false; //是否拦截向上冒泡事件,true:上层监听不到事件
    },
    child: ListView.builder(
        //physics: NeverScrollableScrollPhysics(),//不能滚动了
        controller: _controller,
        padding: const EdgeInsets.only(bottom: 140),
        //scrollDirection: Axis.horizontal,
        itemExtent: 60,
        itemCount: 80,
        itemBuilder: (context, index) {
            return ListTile(
                leading: Icon(Icons.person),
                title: Text('Name'),
                subtitle: Text('Introduction'),
                trailing: IconButton(
                    icon: Icon(Icons.delete_outline),
                ),
            );
        },
    ),
),

支持滑动删除的Dismissible

Dismissible(
    confirmDismiss: (direction) async {
        await Future.delayed(Duration(seconds: 2));
        return true; //是否删除
    },
    onResize: () {
        //即将消失时不断调用
        print('on resizing');
    },
    dismissThresholds: {
        //滑动后自动滑动的百分比
        DismissDirection.startToEnd: 0.4,
        DismissDirection.endToStart: 0.4
    },
    resizeDuration: Duration(seconds: 5), //消失的时间
    movementDuration: Duration(seconds: 5), //指示器滑动时间
    background: Container(color: Colors.red), //从左到右滑动颜色
    secondaryBackground: Container(color: Colors.black), //从右到左滑动颜色
    onDismissed: (direction) {
        //监听
        print(direction);
    },
    key: UniqueKey(),
    child: Container(
        height: 50,
        color: Colors.blue[index % 9 * 100],
    ),
);

实例:GitHub最新动态

class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State {
  final _events = [];

  _refresh() async {
    final res = await http.get("https://api.github.com/events");
    if (res.statusCode == 200) {
      final List json = convert.jsonDecode(res.body);
      // print(json); //Map代表json类型
      setState(() {
        _events.clear();
        _events.addAll(json.map((element) => GitEvent(element)));
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scrollbar(
      child: RefreshIndicator(
        onRefresh: () async {
          await _refresh();
        },
        child: ListView(
          children: _events.map((event) {
            return Dismissible(
              confirmDismiss: (_) async {
                return showDialog(
                  context: context,
                  builder: (_) {
                    return AlertDialog(
                      title: Text('Are you sure?'),
                      content: Text('Do you want to delete this item?'),
                      actions: [
                        FlatButton(
                            onPressed: () {
                              Navigator.of(context).pop(false);
                            },
                            child: Text('Cancel')),
                        FlatButton(
                            onPressed: () {
                              Navigator.of(context).pop(true);
                            },
                            child: Text('Delete'))
                      ],
                    );
                  },
                );
              },
              onDismissed: (_) {
                setState(() {
                  _events.removeWhere((e) => e.id == event.id);
                });
              },
              key: ValueKey(event.id),
              child: ListTile(
                leading: Image.network(
                    'http://www.tobutomi.top/NewsCat/images/avatar/avatar.jpg'),
                title: Text('${event.userName}'),
                subtitle: Text('${event.repoName}'),
              ),
            );
          }).toList(),
        ),
      ),
    );
  }
}

class GitEvent {
  String id;
  String userName;
  String avatarUrl;
  String repoName;
  GitEvent(json) {
    this.id = json['id'];
    this.userName = json['actor']['login'];
    this.avatarUrl = json['actor']['avatar_url'];
    this.repoName = json['repo']['name'];
  }
  @override
  String toString() {
    // TODO: implement toString
    return 'GitEvent{id:$id,userName:$userName,avatarUrl:$avatarUrl,repoName:$repoName}';
  }
}

GridView(二维网格列表)详解

GridView.builder(
    //固定个数
    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 4, //每一行的网格个数
        childAspectRatio: 16 / 9, //修改网格比例
        mainAxisSpacing: 2.0, //上下间隙
        crossAxisSpacing: 4.0, //左右间隙
    ),

    //固定最大宽度
    // gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
    //   childAspectRatio: 16 / 9,
    //   maxCrossAxisExtent: 120,//每一行的个数通过最大宽度来变化
    // ),
    itemCount: 80,
    itemBuilder: (context, index) {
        return Center(
            child: Container(
                width: double.infinity,
                height: 100,
                color: Colors.blue[index % 8 * 100],
                child: Text('$index'),
            ),
        );
    });

趁热打铁再来4个widget

ListWheelScrollView

ListWheelScrollView(
    physics: FixedExtentScrollPhysics(), //停留在中间
    onSelectedItemChanged: (index) => print("selected $index"), //项目选择
    magnification: 2.5, //中间放大
    useMagnifier: true, //是否使用放大镜
    // overAndUnderCenterOpacity: 0.2, //除了中间,其他的透明度
    //  offAxisFraction: -1.5, //轴心的偏移
    diameterRatio: 2.0, //直径比例
    itemExtent: 100,
    children: List.generate(
        20,
        (index) => Container(
            color: Colors.blue,
            child: Text('Hello'),
            alignment: Alignment.center,
        )),
);

拓展,横向

RotatedBox(
    quarterTurns: 1,
    child: ListWheelScrollView(
        physics: FixedExtentScrollPhysics(), //停留在中间
        onSelectedItemChanged: (index) => print("selected $index"), //项目选择
        magnification: 2.5, //中间放大
        useMagnifier: true, //是否使用放大镜
        // overAndUnderCenterOpacity: 0.2, //除了中间,其他的透明度
        //  offAxisFraction: -1.5, //轴心的偏移
        diameterRatio: 2.0, //直径比例
        itemExtent: 100,
        children: List.generate(
            20,
            (index) => RotatedBox(
                quarterTurns: -1,
                child: Container(
                    //color: Colors.blue,
                    child: Text(
                        '$index',
                        style: TextStyle(fontSize: 48),
                    ),
                    alignment: Alignment.center,
                ),
            )),
    ),
);

PageView

PageView(
    pageSnapping: true, //可以不停在一个页面上
    scrollDirection: Axis.vertical, //竖直方向
    children: [
        Container(color: Colors.blue),
        Container(color: Colors.orange)
    ],
    onPageChanged: (value) => print('selected:$value'), //监听
);

ReorderableListView

ReorderableListView(
    children: List.generate(
        20, (index) => Text('index is $index', key: UniqueKey())),
    onReorder: (int oldIndex, int newIndex) =>
    print('moved from $oldIndex to $newIndex'));

SingleChildScrollView

//包裹上后,布局溢出的时候可以滚动
SingleChildScrollView(
    child: Column(
        children: [
            FlutterLogo(size: 300),
            FlutterLogo(size: 400),
        ],
    ),
);

相关