簡體   English   中英

Flutter - 包含來自數據庫的數據的動態列表

[英]Flutter - Dynamic list with data coming from the database

我需要使用來自數據庫的數據創建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),
            ),
          ],
        ),
      )
    );
  }
}

可能還有其他問題,但作為一個開始,我認為這個代碼

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

我找到了解決方案,根據Flutter - Build Widgets動態Flutter - 將動態生成的元素與硬編碼元素結合起來並在這個問題中

作為SimpleDialog只接受一個List類型的Widget - <Widget>[]我聲明變量tiles類型的List<Widget> - List<Widget> tiles; 並創建了List<Widget>類型的函數 - List<Widget> buildTile(int counter) {... - 能夠返回List<Widget>

由於Navigator.pop (context, ...我需要在Widget build(BuildContext context) {...創建buildTile()函數Widget build(BuildContext context) {...

buildTile()函數中,根據來自數據庫的結果,我添加了一個for()以插入到Widget類型列表中,因為需要多個DialogItem Widgets

並使用setState(() {...})包裝更新狀態的代碼,如GünterZöchbauer所述

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM