Flutter练习demo

Listview 常用属性

flutter中使listView高度随item自适应_上拉加载

reverse 和 shrinkWrap使用注意
  1. 正常Listview 内容不够一屏(不设置 reverse 和 shrinkWrap属性)
  2. reverse = true
    默认false
    scrollDirection = Axis.vertical false:布局从上倒下 true:从下往上
    scrollDirection = Axis.horizontal = 默认 false:布局从左倒右 true:从右往左
  3. reverse=true shrinkWrap=true
    shrinkWrap:默认false 滚动方向的滚动视图内容是否应该由正在查看的内容所决定

    三图对比可以验证 shrinkWrap=true,滚动方向的滚动视图内容是否应该由正在查看的内容所决定

ListTitle常用属性

flutter中使listView高度随item自适应_ListView_02

Listview和ListTitle的简单使用

flutter中使listView高度随item自适应_下拉刷新_03

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
class ListViewPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: Icon(Icons.home),
          title: Text("ListView"),
        ),
        body: ListView(
          scrollDirection: Axis.vertical,
//          reverse: true,
          //vertical = 默认 false:布局从上倒下   true:从下往上
          //horizontal = 默认 false:布局从左倒右   true:从右往左
//          shrinkWrap: true,
          padding: EdgeInsets.all(20),
          children: <Widget>[
            ListTile(
              enabled: false, // false  onTap   onLongPress失效
              onTap: () {
                _toOnTap();
              },
              onLongPress: () {
                _toLongPress();
              },
              title: Text("ListTitle"),
              subtitle: Text("我是ListTitle的副标题"),
              leading: Icon(
                Icons.save,
                color: Color(0x99ff22ee),
              ),
              trailing: Icon(Icons.search),
            ),
            Center(
                child: Container(
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.all(Radius.circular(150)),
                  color: Colors.blue,
                  image: DecorationImage(
                      image: AssetImage('images/s.jpg'), fit: BoxFit.cover)),
              width: 100,
              height: 100,
            )),
            Center(
              child: ClipOval(
                child: Image.asset(
                  'images/x.jpg',
                  width: 100,
                  height: 100,
                  fit: BoxFit.cover,
                ),
              ),
            ),
            Center(
              child: ClipOval(
                child: Image.file(
                  File(
                      '/storage/emulated/0/Android/data/c.s.sflutter/files/a.jpg'),
                  width: 100,
                  height: 100,
                  fit: BoxFit.cover,
                ),
              ),
            ),
            Center(
              child: ClipOval(
                child: Image.network(
                  'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564720497900&di=e563c915685bceb398e4692b4ebab4e0&imgtype=jpg&src=http%3A%2F%2Fimg0.imgtn.bdimg.com%2Fit%2Fu%3D551180330%2C2986440005%26fm%3D214%26gp%3D0.jpg',
                  width: 100,
                  height: 100,
                  fit: BoxFit.cover,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

_toOnTap() {
  print('ListTitle  =  _toOnTap');
}

_toLongPress() {
  print('ListTitle  =  _toLongPress');
}

ListView动态加载Item

方式1
import 'package:flutter/material.dart';
class DongtaiListViewPage extends StatelessWidget {

  List<Widget> _getList() {
    List<Widget> list = new List();
    for (var i = 0; i < 10; i++) {
      list.add(ListTile(
          title: Text("ListTile = $i"), subtitle: Text("subtitle = $i")));
    }
    return list;
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: Icon(Icons.home),
          title: Text("ListView"),
        ),
        body: ListView(
          scrollDirection: Axis.vertical,
//          reverse: true,
          //vertical = 默认 false:布局从上倒下   true:从下往上
          //horizontal = 默认 false:布局从左倒右   true:从右往左
//          shrinkWrap: true,
          padding: EdgeInsets.all(20),
          children: _getList(),
        ),
      ),
    );
  }
}
方式2
List<Widget> _getListItem() {
    return [
      ListTile(
        title: Text("ListTile 1"),
      ),
      ListTile(
        title: Text("ListTile 2"),
      ),
      ListTile(
        title: Text("ListTile 3"),
      ),
      ListTile(
        title: Text("ListTile 4"),
      ),
    ];
  }
  直接把方式1的 children: _getList(),换成 children: _getListItem(), 即可
方式3

通过构造方法里面初始化数据

import 'package:flutter/material.dart';

class ListViewPage3 extends StatelessWidget {
  List<String> list = new List();

  ListViewPage3() : super() {
    for (var i = 0; i < 10; i++) {
      list.add("ListItem = $i");
    }
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            leading: Icon(Icons.home),
            title: Text("ListView"),
          ),
          body: ListView.builder(
              itemCount: list.length,
              itemBuilder: (context, i) {
                return ListTile(
                  title: Text("${list[i]}"),
                  leading: Icon(Icons.library_music),
                  subtitle: Text("副标题 ${list[i]}"),
                );
              })),
    );
  }
}

ListView实现下拉刷新(RefreshIndicator)

准备:
  1. StatelessWidget 要改成继承 StatefulWidget
  2. 准备一个正常的列表
  3. 使用RefreshIndicator
    效果图:
    刷新界面可重复看预览效果!
void main() => runApp(MyApp());
//StatelessWidget 要改成继承 StatefulWidget
class MyApp extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    return RefreshListViewPage();
  }

import 'package:flutter/material.dart';

class RefreshListViewPage extends State {
  List<String> list = new List();
  RefreshListViewPage() : super() {
    for (var i = 0; i < 30; i++) {
      list.add("ListItem = $i");
      print("$i");
    }
  }
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: Icon(Icons.home),
          title: Text("ListView"),
        ),
        //RefreshIndicator 使用
        body: RefreshIndicator(
          onRefresh: _onRefresh,
          child: ListView.builder(
            itemCount: list.length,
            itemBuilder: (context, i) {
              return ListTile(
                title: Text("${list[i]}"),
                leading: Icon(Icons.library_music),
                subtitle: Text("副标题 ${list[i]}"),
              );
            },
          ),
        ),
      ),
    );
  }

// 模拟下拉刷新的网络请求
  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        List<String> refreshList = new List();
        for (var i = 0; i < 4; i++) {
          refreshList.add("下拉刷新 = $i");
        }
        refreshList.addAll(list);
        list.clear();
        list.addAll(refreshList);
      });
    });
  }
}

ListView实现上拉加载

ListView.builder中有一个属性 controller 可借助这个属性实现Listview的滑动监听

效果图:

刷新界面可重复看预览效果!

flutter中使listView高度随item自适应_ListView_04


需要复写两个方法

// 状态初始化完成
void initState() {
    // TODO: implement initState
    super.initState();

  }

// 释放资源
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
   
  }
  1. 在ListView.builder中使用controller属性,初始化ScrollController
ScrollController _toSontroller = ScrollController();
  1. 重写initState、 dispose两个方法
  2. 添加滑动监听
ScrollController _toSontroller = ScrollController();
//状态被初始化完成
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
      // 上拉加载  step 3
    _toSontroller.addListener(() {
      if (_toSontroller.position.pixels ==
          _toSontroller.position.maxScrollExtent) {
        print("列表到底啦");
        // 列表滑动到底时,执行上拉加载数据
         // 上拉加载  step 5
        _onLoadMore();
      }
    });
  }
  1. 对 itemCount、itemBuilder的属性返回进行修改
//上拉加载 step 4
itemCount: list.length + 1, // 因为增加了一个上啦加载的Widget,所以这里增加1
itemBuilder: _loadWidget, // 返回的Widget,要区分时正常数据的item的Widget,还是上拉加载的Widget

  /**
   * 区分上拉时返回的Widget
   * */
  Widget _loadWidget(BuildContext ctx, int i) {
    if (i < list.length) {
      // 返回正常Item的Widget
      return ListTile(
        title: Text("${list[i]}"),
        leading: Icon(Icons.library_music),
        subtitle: Text("副标题 ${list[i]}"),
      );
    } else {
      // 返回上拉加载布局的Widget
      return Center(
        child: Container(
          alignment: Alignment.center,
          color: Colors.red,
          width: double.infinity,
          height: 80,
          child: Text("正在加载更多..."),
        ),
      );
    }
  }
  1. 提供上拉加载数据
/**
   *上拉加载
   * */
  Future<Null> _onLoadMore() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        List<String> refreshList = new List();
        for (var i = 0; i < 6; i++) {
          refreshList.add("上拉加载 = $i");
        }
        list.addAll(refreshList);
      });
    });
  }

这5步就实现上拉加载的效果了,具体细节可以再完善,例如真实项目中加载中正在请求数据,在上拉不应该再次请求等等、、

上拉加载、下拉刷新完整代码

import 'package:flutter/material.dart';

class RefreshListViewPage extends State {
  List<String> list = new List();

  RefreshListViewPage() : super() {
    for (var i = 0; i < 30; i++) {
      list.add("ListItem = $i");
      print("$i");
    }
  }

  //上拉加载 step 1
  ScrollController _toSontroller = ScrollController();
  //上拉加载 step 2
//状态被初始化完成
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
     // 上拉加载  step 3
    _toSontroller.addListener(() {
      if (_toSontroller.position.pixels ==
          _toSontroller.position.maxScrollExtent) {
        print("列表到底啦");
          // 上拉加载  step 5
        _onLoadMore();
      }
    });
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _toSontroller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: Icon(Icons.home),
          title: Text("ListView"),
        ),
        body: RefreshIndicator(
          onRefresh: _onRefresh,
          child: ListView.builder(
          //上拉加载 step 4 
            itemCount: list.length + 1,
            itemBuilder: _loadWidget,
            // 上拉加载 step 1
            controller: _toSontroller,
          ),
        ),
      ),
    );
  }

  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        List<String> refreshList = new List();
        for (var i = 0; i < 4; i++) {
          refreshList.add("下拉刷新 = $i");
        }
        refreshList.addAll(list);
        list.clear();
        list.addAll(refreshList);
      });
    });
  }

  /**
   *上拉加载
   * */
  Future<Null> _onLoadMore() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        List<String> refreshList = new List();
        for (var i = 0; i < 6; i++) {
          refreshList.add("上拉加载 = $i");
        }
        list.addAll(refreshList);
      });
    });
  }

  /**
   * 区分上拉时返回的Widget
   * */
  Widget _loadWidget(BuildContext ctx, int i) {
    if (i < list.length) {
      // 返回正常Item的Widget
      return ListTile(
        title: Text("${list[i]}"),
        leading: Icon(Icons.library_music),
        subtitle: Text("副标题 ${list[i]}"),
      );
    } else {
      // 返回上拉加载布局的Widget
      return Center(
        child: Container(
          alignment: Alignment.center,
          color: Colors.red,
          width: double.infinity,
          height: 80,
          child: Text("正在加载更多..."),
        ),
      );
    }
  }
}

完成效果图

flutter中使listView高度随item自适应_下拉刷新_05