【问题标题】:Flutter - Dynamic list with data coming from the databaseFlutter - 来自数据库的数据的动态列表
【发布时间】:2018-04-18 18:58:43
【问题描述】:

我需要使用来自数据库的数据创建 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}]

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),
            ),
          ],
        ),
      )
    );
  }
}

【问题讨论】:

    标签: database sqlite dart flutter


    【解决方案1】:

    可能还有其他问题,但作为开始,我认为这段代码

    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}]
              });
            });
          }
        );
      }
    

    【讨论】:

    • in for() 出现错误,[dart] Expected to find ')'. [dart] Expected to find ']'.[dart] Expected an identifier. 但它正确关闭,似乎不允许将 if()for() 放入 children list: &lt;Widget&gt;[]
    • 嗯,我认为不能在 List 构造函数中使用 for,您可能可以做一些事情 like this
    • Duh,我完全错过了,你不需要手动构建列表大声笑 - 很好的解决方案 :)
    • 感谢您的帮助,但new List(this.number).map((i) =&gt;... 解决方案出现以下错误Invalid argument(s) _List.[] (dart:core-patch/dart:core/array.dart:11) 当我点击按钮时出现错误
    • 但是感谢您生成列表而不是生成列表元素的想法,我找到了基于其他堆栈流的解决方案
    【解决方案2】:

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

    由于SimpleDialog 只接受List 类型为Widget - &lt;Widget&gt;[] 我声明了一个tiles 类型为List&lt;Widget&gt; - List&lt;Widget&gt; tiles; 的变量并创建了一个List&lt;Widget&gt; - @987654333 类型的函数@ - 能够返回List&lt;Widget&gt;

    由于Navigator.pop (context, ...,我需要在Widget build(BuildContext context) {... 中创建buildTile() 函数

    buildTile() 函数中,根据来自数据库的结果,我添加了一个for() 以插入Widget 类型列表,因为需要多个DialogItem Widgets

    按照 Günter Zöchbauer 的解释,用 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}]
    })
    

    完整的代码和演示如下:

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

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

    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<Widget> tiles;
    
      List colors = [
        const Color(0xFFFFA500),
        const Color(0xFF279605),
        const Color(0xFF005959)
      ];
    
      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}]
              });          
            });
          }
        );
      }
    
      @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) {
    
        List<Widget> buildTile(int counter) {
          this.tiles = [];
          for(var i = 0; i < counter; i++) {
            this.tiles.add(
              new DialogItem(
                icon: Icons.brightness_1,
                color: this.colors[
                  this.listCategory[i]['color']
                ],
                text: this.listCategory[i]['name'],
                onPressed: () {
                  Navigator.pop(context, this.listCategory[i]['name']);
                }
              )
            );
          }
          return this.tiles;
        }
    
        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: buildTile(this.number)
                  )
                );
              },
              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),
                ),
              ],
            ),
          )
        );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-01-19
      • 1970-01-01
      • 2010-11-22
      • 2011-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多