Flutter - 包含来自数据库的数据的动态列表

时间:2017-11-06 15:05:30

标签: database sqlite dart flutter

我需要使用来自数据库的数据创建DialogItem小部件。我尝试使用for(){},但它没有用。

你能帮我解决这个问题吗?

我把使用过的代码和有效的证据放在一起,只是不能使用数据库数据的DialogItem动态列表。

要使用下面的代码,您需要将sqflitepath_provider依赖项插入pubspec.yaml,因此:

dependencies:
  sqflite: any
  path_provider: any
  flutter:
    sdk: flutter

DatabaseClient类将创建包含3条记录的数据库。

在gif中只显示foo1,正确的是显示来自数据库的列表的所有值:

[{name: foo1, color: 0}, {name: foo2, color: 1}, {name: foo3, color: 2}]

enter image description here

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  DatabaseClient _db = new DatabaseClient();
  int number;
  List listCategory;

  List colors = [
    const Color(0xFFFFA500),
    const Color(0xFF279605),
    const Color(0xFF005959)
  ];

  createdb() async {
    await _db.create().then(
      (data){
        _db.countCategory().then((list){
          this.number = list[0][0]['COUNT(*)']; //3
          this.listCategory = list[1];
          //[{name: foo1, color: 0}, {name: foo2, color: 1}, {name: foo3, color: 2}]
        });
      }
    );
  }

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

  void showCategoryDialog<T>({ BuildContext context, Widget child }) {
    showDialog<T>(
      context: context,
      child: child,
    )
    .then<Null>((T value) {
      if (value != null) {
        setState(() { print(value); });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(),
      body: new Center(
        child: new RaisedButton(
          onPressed: (){           
            showCategoryDialog<String>(
              context: context,
              child: new SimpleDialog(
                title: const Text('Categories'),
                children: <Widget>[
                  //for(var i = 0; i < this.number; i++) {
                    new DialogItem(
                      icon: Icons.brightness_1,
                      color: this.colors[
                        this.listCategory[0]['color']
                        //the zero should be dynamic going from 0 to 2 with the for(){}
                        //but o for(){} dont work
                      ],
                      text: this.listCategory[0]['name'],
                      onPressed: () {
                        Navigator.pop(context, this.listCategory[0]['name']);
                      }
                    ),
                  //}                  
                ]
              )
            );
          },
          child: new Text("ListButton"),
        )
      ),
    );
  }
}

//Creating Database with some data and two queries
class DatabaseClient {
  Database db;

  Future create() async {
    Directory path = await getApplicationDocumentsDirectory();
    String dbPath = join(path.path, "database.db");
    db = await openDatabase(dbPath, version: 1, onCreate: this._create);
  }

  Future _create(Database db, int version) async {
    await db.execute("""
            CREATE TABLE category (
              id INTEGER PRIMARY KEY,
              name TEXT NOT NULL,
              color INTEGER NOT NULL
            )""");
    await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo1', 0)");
    await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo2', 1)");
    await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo3', 2)");
  }

  Future countCategory() async {
    Directory path = await getApplicationDocumentsDirectory();
    String dbPath = join(path.path, "database.db");
    Database db = await openDatabase(dbPath);

    var count = await db.rawQuery("SELECT COUNT(*) FROM category");
    List list = await db.rawQuery('SELECT name, color FROM category');
    await db.close();

    return [count, list];
  }
}

//Class of Dialog Item
class DialogItem extends StatelessWidget {
  DialogItem({ 
    Key key,
    this.icon,
    this.size,
    this.color,
    this.text,
    this.onPressed }) : super(key: key);

  final IconData icon;
  double size = 36.0;
  final Color color;
  final String text;
  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) {
    return new SimpleDialogOption(
      onPressed: onPressed,
      child: new Container(
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            new Container(              
              child: new Container(
                margin: size == 16.0 ? new EdgeInsets.only(left: 7.0) : null,
                child: new Icon(icon, size: size, color: color),
              )                
            ),        
            new Padding(
              padding: size == 16.0 ?
                const EdgeInsets.only(left: 17.0) :
                const EdgeInsets.only(left: 16.0),
              child: new Text(text),
            ),
          ],
        ),
      )
    );
  }
}

2 个答案:

答案 0 :(得分:4)

可能还有其他问题,但首先,我认为这段代码

for(var i = 0; i < this.number; i++) {
  ...
}

应改为

children: this.number == null ? null :  
  new List(this.number).map((i) => 
    new DialogItem(
      icon: Icons.brightness_1,
      color: this.colors[
        this.listCategory[0]['color']
        //the zero should be dynamic going from 0 to 2 with the for(){}
        //but o for(){} dont work
      ],
      text: this.listCategory[0]['name'],
      onPressed: () {
        Navigator.pop(context, this.listCategory[0]['name']);
      }
    ).toList(),

this.numbernull时未抛出异常(尚未从数据库收到响应)。

并使用setState(() {...})

包装更新状态的代码
  createdb() async {
    await _db.create().then(
      (data){
        _db.countCategory().then((list){
          setState(() {
            this.number = list[0][0]['COUNT(*)']; //3
            this.listCategory = list[1];
          //[{name: foo1, color: 0}, {name: foo2, color: 1}, {name: foo3, color: 2}]
          });
        });
      }
    );
  }

答案 1 :(得分:0)

根据Flutter - Build Widgets dynamicallyFlutter - Combine dynamically generated elements with hard-coded ones以及此问题,我找到了解决方案

由于SimpleDialog仅接受List类型Widget - <Widget>[],我声明类型为tiles的变量List<Widget> - {{1}并创建了一个List<Widget> tiles;类型的函数 - List<Widget> - 以便能够返回List<Widget> buildTile(int counter) {...

由于List<Widget>我需要在Navigator.pop (context, ...

中创建buildTile()函数

Widget build(BuildContext context) {...函数中,根据来自数据库的结果,我添加了buildTile()以插入for()类型列表,因为需要许多Widget < / p>

并根据GünterZöchbauer解释用DialogItem Widgets包装更新状态的代码

setState(() {...})

完整的代码以及演示如下:

要使用下面的代码,您需要将setState(() { this.number = list[0][0]['COUNT(*)']; //3 this.listCategory = list[1]; //[{name: foo1, color: 0}, {name: foo2, color: 1}, {name: foo3, color: 2}] }) sqflite依赖项插入path_provider,因此:

pubspec.yaml

enter image description here

dependencies:
  sqflite: any
  path_provider: any
  flutter:
    sdk: flutter