[Flutter-21] ListView & Json

Json

1. Json 使用

  • 01: 现将json文件拖入到新建assets文件夹下
  • 02: 在pubspec.yaml 文件下配置路径
  # To add assets to your application, add an assets section, like this:
  assets:
    - assets/flutter.json
  #   - images/a_dot_burr.jpeg
  #   - images/a_dot_ham.jpeg

2. Json 读取

  • 01: 导入头文件Buddle: import 'package:flutter/services.dart' show rootBundle;
  • 02: 通过Future 异步获取:
  • 03: 创建model 模型进行遍历dict转模型
import 'dart:convert';

import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter_listview_json/homeModel.dart';

Future<List<HomeModel>> getHomeViweModel() async {
  // 读取json文件
  String jsonString = await rootBundle.loadString('assets/flutter.json');

  // 转成list或者map
  final result = json.decode(jsonString);

  // 遍历转成模型
  List<HomeModel> models = [];
  for (Map<String, dynamic> map in result) {
    models.add(HomeModel.withMap(map));
  }

  // 返回模型数据
  return models;
}


class HomeModel {
  String title;
  String description;
  String img;

  HomeModel(this.title, this.description, this.img);

  HomeModel.withMap(Map<String, dynamic> map) {
    this.title = map['title'];
    this.description = map['description'];
    this.img = map['img'];
  }
}

ListView

1. ListView 基本使用

  • ListView可以沿一个方向(垂直或水平方向,默认是垂直方向)来排列其所有子Widget。
// ListView 的基本直接使用
class Content extends StatelessWidget {
  final TextStyle textStyle = TextStyle(fontSize: 20, color: Colors.redAccent);
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        Padding(
          padding: EdgeInsets.all(8),
          child: Text("雪野茫茫,你知道一颗小草的梦吗?", style: textStyle),
        ),
        Padding(
          padding: EdgeInsets.all(8),
          child: Text("窗前托腮沉思的少女,你是想做一朵云的诗,还是做一只蝶的画?", style: textStyle),
        ),
        Padding(
          padding: EdgeInsets.all(8),
          child: Text("没有泪水的人,她的眼睛是干涸的;没有梦的人,他的夜是黑暗的。", style: textStyle),
        ),
      ],
    );
  }
}

2. ListTile

  • 在开发中,我们经常见到一种列表,有一个图标或图片(Icon), 有一个标题(Title),有一个子标题(Subtitle),还有尾部一个图标(Icon)
class Content2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        ListTile(
          leading: Icon(
            Icons.people,
            size: 20,
            color: Colors.red,
          ),
          title: Text('联系人:ListTile'),
          subtitle: Text('联系人信息'),
          trailing: Icon(Icons.arrow_forward_ios),
          tileColor: Colors.greenAccent,
        ),
        ListTile(
          leading: Icon(
            Icons.email,
            size: 20,
          ),
          title: Text('邮箱:ListTile'),
          subtitle: Text('邮箱地址信息'),
          trailing: Icon(Icons.arrow_forward_ios),
        ),
        ListTile(
          leading: Icon(
            Icons.message,
            size: 20,
          ),
          title: Text('消息:ListTile'),
          subtitle: Text('消息详情信息'),
          trailing: Icon(Icons.arrow_forward_ios),
          tileColor: Colors.yellow,
        ),
        ListTile(
          leading: Icon(
            Icons.map,
            size: 20,
          ),
          title: Text('地址:ListTile'),
          subtitle: Text('地址详情信息'),
          trailing: Icon(Icons.arrow_forward_ios),
          tileColor: Colors.blue,
        ),
      ],
    );
  }
}

3. ListView 水平方向使用

  • ListView 滚动方向: 水平和垂直
  • 水平: 需要设置Container宽度或者设置每一个item的宽度itemExtent
  • 垂直: 不需要设置其他
/* ListView 滚动方向: 水平和垂直
水平: 需要设置Container宽度或者设置每一个item的宽度itemExtent
垂直: 不需要设置其他
*/
class Content3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      scrollDirection: Axis.horizontal,
      itemExtent: 375, // 设置所有item的统一宽度
      children: [
        Container(color: Colors.red, width: 100), // 设置每一个独立的宽度
        Container(color: Colors.greenAccent, width: 200),
        Container(color: Colors.blue, width: 300),
        Container(color: Colors.purple, width: 300),
        Container(color: Colors.orange, width: 300),
      ],
    );
  }
}

4. ListView.build 基本使用

  • 通过构造函数children传入所有子widget会一次性创建所有的widget、性能很差、而且会增加首屏的渲染时间. 我们可以使用ListView.build来构建Widget,提高性能.
  • ListView.build:
  • 适用于数据比较多的时候
  • 当列表滚动到对应位置的时候、ListView就会自动调用该方法来创建对应的子Widget,类型是IndexedWidgetBuilder, 是一个函数类型.
  • itemCount: 表示列表项的数量,如果为空,则表示ListView为无限列表.
class Content4 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 100,
      itemExtent: 200,
      itemBuilder: (BuildContext context, int index) {
        print('###: index:$index');
        return ListTile(
          title: Text('标题$index'),
          subtitle: Text('详情内容$index'),
          tileColor: (index % 2 == 0) ? Colors.orange : Colors.purple,
        );
      },
    );
  }
}

5. ListView.build 动态数据展示

  • 由于json数据获取是异步加载的、无法使用statelessWidget来渲染
  • 刚开始界面并不会显示数据、后面json加载出来数据后、再次展示加载的数据。
class Content5 extends StatefulWidget {
  @override
  _Content5State createState() => _Content5State();
}

class _Content5State extends State<Content5> {
  List<HomeModel> models = [];

  @override
  void initState() {
    getHomeViweModel().then((value) {
      setState(() {
        this.models = value;
      });
    });

    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: this.models.length,
        itemBuilder: (BuildContext context, int index) {
          return Padding(
            padding: EdgeInsets.all(0),
            child:
                Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
              Image.network(
                this.models[index].img,
                fit: BoxFit.fitWidth,
                width: MediaQuery.of(context).size.width,
              ),
              SizedBox(height: 10),
              Text(
                '电影名: ${this.models[index].title}',
                style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
              ),
              SizedBox(height: 10),
              Text(
                '电影简介: ${this.models[index].description}',
                style: TextStyle(fontSize: 10),
              ),
              SizedBox(height: 10),
              Container(
                color: Colors.grey,
                width: MediaQuery.of(context).size.width,
                height: 0,
              ),
            ]),
          );
        });
  }
}

6. ListView.separated 使用

  • ListView.separated 比ListView.build 多了一个参数 separatorBuild参数, 该参数是一个分割器生成器
  • Divider: 分割器生成器Widget
class Content6 extends StatelessWidget {
  Divider blueColor = Divider(color: Colors.blue);
  Divider redColor = Divider(color: Colors.red);

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      itemBuilder: (BuildContext context, int index) {
        return ListTile(
          leading: Icon(Icons.people),
          title: Text('联系人: ${index + 1}'),
          subtitle: Text('联系人电话: ${index + 1}'),
        );
      },
      separatorBuilder: (BuildContext context, int index) {
        return Divider(
          color: Colors.grey,
          height: 0,
          thickness: 0.25, // 厚度
        );
        return index % 2 == 0 ? blueColor : redColor;
      },
      itemCount: 20,
    );
  }
}

posted @ 2021-07-19 16:05  comefromchina  阅读(83)  评论(0编辑  收藏  举报