Flutter数据库编辑器插件drift_editors的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter数据库编辑器插件drift_editors的使用

描述

这个包的出现是因为我发现我在编写用于编辑用drift编写的行的用户界面时花费了大量时间。这不仅非常无聊,而且缺乏创造性,我觉得这些工作应该由更动态的东西来处理,这样我就可以继续添加各种编辑器的功能。

此外,即使我已经有了package:backstreets_widgets,我发现我还是在为设置或管理页面编写大量的代码来创建标签界面。

引入 drift_editors

我制作了drift_editors来减轻至少更新行的工作量。现在,我不再需要写这样的代码:

final database = ref.watch(databaseProvider);
final dao = database.missionsDao;
final value = ref.watch(missionProvider(missionId));
return SimpleScaffold(
  title: 'Edit Mission',
  body: value.when(
    data: (final mission) => ListView(
      shrinkWrap: true,
      children: [
        TextListTile(
          value: mission.name,
          onChanged: (final name) async {
            await dao.editMission(
              mission: mission,
              companion: MissionsCompanion(name: Value(name)),
            );
            invalidateProviders(ref);
          },
          header: 'Mission name',
        ),
        PointListTile(
          point: Point(mission.x, mission.y),
          onChanged: (final point) async {
            await dao.editMission(
              mission: mission,
              companion: MissionsCompanion(
                x: Value(point.x),
                y: Value(point.y),
              ),
            );
            invalidateProviders(ref);
          },
          title: 'Initial coordinates',
        ),
      ],
    ),
    error: ErrorListView.withPositional,
    loading: LoadingWidget.new,
  ),
);

而是可以写这样的代码:

final database = ref.watch(databaseProvider);
final missions = database.missions;
final value = ref.watch(missionProvider(missionId));
return value.when(
  data: (final mission) {
    final id = mission.id;
    return DriftEditorScreen(
      columnHandlers: [
        StringColumnHandler(
          value: mission.name,
          column: missions.name,
        ),
        PointColumnHandler(
          xColumn: missions.x,
          yColumn: missions.y,
          value: Point(mission.x, mission.y),
          title: 'Initial coordinates',
        ),
      ],
      title: 'Edit Mission',
      database: database,
      tableInfo: missions,
      primaryKeyColumn: missions.id,
      primaryKey: id,
      onChanged: () => invalidateProviders(ref),
    );
  },
  error: ErrorScreen.withPositional,
  loading: LoadingScreen.new,
);

如果你更喜欢自己编写屏幕,可以直接使用 [ColumnsListView] 小部件。

完整示例

主要文件结构

假设你的项目结构如下:

lib/
├── main.dart
├── database/
│   ├── mission_dao.dart
│   └── mission_database.dart
└── widgets/
    └── drift_editors_screen.dart

数据库定义

mission_database.dart

import 'package:drift/drift.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart' as sqflite;

part 'mission_database.g.dart';

class Missions extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get name => text().withLength(min: 1, max: 100)();
  RealColumn get x => real()();
  RealColumn get y => real()();
}

@DriftDatabase(tables: [Missions])
class MyDatabase extends _$MyDatabase {
  MyDatabase() : super(_openConnection());

  static MyDatabase open() {
    final instance = MyDatabase();
    instance.into(instance.missions).insert(MissionsCompanion.insert(name: 'Default Mission', x: 0, y: 0));
    return instance;
  }

  [@override](/user/override)
  int get schemaVersion => 1;
}

LazyDatabase _openConnection() {
  return LazyDatabase(() async {
    final dbFolder = await getApplicationDocumentsDirectory();
    final file = File('${dbFolder.path}/missions.db');
    return sqflite.databaseFactoryIo.openDatabase(file.path);
  });
}

mission_dao.dart

import 'package:my_project/database/mission_database.dart';

class MissionsDao {
  final MyDatabase _db;

  MissionsDao(this._db);

  Future<void> editMission({required MissionsCompanion companion, required int id}) async {
    await _db.update(_db.missions).replace(companion, where: 'id = ?', whereArgs: [id]);
  }
}

编辑器屏幕

drift_editors_screen.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:drift_editors/drift_editors.dart';
import 'package:my_project/database/mission_database.dart';
import 'package:my_project/widgets/loading_screen.dart';
import 'package:my_project/widgets/error_screen.dart';

final databaseProvider = Provider((ref) => MyDatabase.open());

class DriftEditorScreen extends ConsumerWidget {
  final List<ColumnHandler> columnHandlers;
  final String title;
  final MyDatabase database;
  final TableInfo<Missions, dynamic> tableInfo;
  final Column<Missions, dynamic> primaryKeyColumn;
  final int primaryKey;
  final VoidCallback onChanged;

  DriftEditorScreen({
    required this.columnHandlers,
    required this.title,
    required this.database,
    required this.tableInfo,
    required this.primaryKeyColumn,
    required this.primaryKey,
    required this.onChanged,
  });

  [@override](/user/override)
  Widget build(BuildContext context, ScopedReader watch) {
    final value = watch(missionProvider(primaryKey));

    return value.when(
      data: (final mission) {
        return Scaffold(
          appBar: AppBar(title: Text(title)),
          body: DriftEditor(
            columnHandlers: columnHandlers,
            database: database,
            tableInfo: tableInfo,
            primaryKeyColumn: primaryKeyColumn,
            primaryKey: primaryKey,
            onChanged: onChanged,
          ),
        );
      },
      error: (error, stackTrace) => ErrorScreen.withPositional(error, stackTrace),
      loading: () => LoadingScreen(),
    );
  }
}

主文件

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:my_project/database/mission_database.dart';
import 'package:my_project/widgets/drift_editors_screen.dart';

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DriftEditorScreenPage(),
    );
  }
}

class DriftEditorScreenPage extends ConsumerWidget {
  [@override](/user/override)
  Widget build(BuildContext context, ScopedReader watch) {
    final database = watch(databaseProvider);
    final missions = database.missions;
    final missionId = 1; // 假设我们正在编辑ID为1的使命

    return DriftEditorScreen(
      columnHandlers: [
        StringColumnHandler(
          value: 'Default Mission', // 假设这是初始值
          column: missions.name,
        ),
        PointColumnHandler(
          xColumn: missions.x,
          yColumn: missions.y,
          value: Point(0, 0), // 假设这是初始坐标
          title: 'Initial coordinates',
        ),
      ],
      title: 'Edit Mission',
      database: database,
      tableInfo: missions,
      primaryKeyColumn: missions.id,
      primaryKey: missionId,
      onChanged: () {},
    );
  }
}

更多关于Flutter数据库编辑器插件drift_editors的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据库编辑器插件drift_editors的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用drift_editors插件的一个示例。drift_editors是一个用于与drift(一个基于SQLite的Flutter数据库库)集成的数据库编辑器插件,它提供了图形界面来编辑数据库的内容。

首先,确保你的Flutter项目中已经包含了driftdrift_dev依赖项,以及drift_editors插件。在pubspec.yaml文件中添加以下依赖项:

dependencies:
  flutter:
    sdk: flutter
  drift: ^x.y.z  # 替换为最新版本号
  drift_dev: ^x.y.z  # 开发工具,仅在开发时使用

dev_dependencies:
  build_runner: ^x.y.z
  drift_generator: ^x.y.z
  drift_editors: ^x.y.z  # 添加drift_editors插件

然后,运行flutter pub get来安装这些依赖项。

接下来,你需要设置drift数据库。创建一个数据模型,并生成相应的数据库代码。例如,创建一个简单的User表:

// user.dart
import 'package:drift/drift.dart';

part 'user.g.dart';

@DataClassName('User')
class Users extends Table {
  IntColumn get id => integer().autoIncrement().primaryKey();
  TextColumn get name => text().withDefault(Constant('Unknown'));
  TextColumn get email => text().nullable();
}

运行flutter pub run build_runner build来生成数据访问对象(DAO)和数据库类。

现在,你可以创建一个数据库实例并使用drift_editors来编辑它。以下是一个完整的示例,展示如何在Flutter应用中集成drift_editors

// main.dart
import 'package:flutter/material.dart';
import 'package:drift/drift.dart';
import 'package:drift_editors/drift_editors.dart';
import 'user.dart';
import 'package:your_app_name/your_database.g.dart';  // 确保导入生成的数据库文件

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Drift Editors Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> {
  late DatabaseConnection _db;

  @override
  void initState() {
    super.initState();
    // 打开数据库连接
    _db = DatabaseConnection.memory(); // 或者使用 DatabaseConnection.connect('path_to_db.sqlite')
    final database = YourDatabase(_db);
    database.createAllTables();

    // 示例:插入一些初始数据
    final userDao = database.userDao;
    userDao.intoUsers().insertAll([
      UserCompanion.insert(name: Value('Alice'), email: Value('alice@example.com')),
      UserCompanion.insert(name: Value('Bob'), email: Value('bob@example.com')),
    ]);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Drift Editors Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            // 打开 Drift Editors 界面
            final result = await showDialog<bool>(
              context: context,
              builder: (context) {
                return DriftEditorsDialog(
                  databaseConnection: _db,
                  title: 'Edit Database',
                );
              },
            );

            if (result == true) {
              // 用户点击了保存按钮,可以在这里处理保存后的逻辑
              print('Database edited and saved.');
            }
          },
          child: Text('Open Database Editor'),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _db.close();
    super.dispose();
  }
}

在上面的代码中,我们创建了一个简单的Flutter应用,其中包含一个按钮,点击该按钮会打开一个DriftEditorsDialog对话框,允许用户编辑数据库。注意,这里使用的是内存数据库(DatabaseConnection.memory()),你可以根据需要更改为文件数据库。

请确保将your_app_nameyour_database.g.dart替换为你的实际项目名和生成的数据库文件名。

这个示例展示了如何在Flutter应用中集成drift_editors插件,并允许用户通过图形界面编辑数据库。

回到顶部