반응형
SQLite를 사용하여 To-Do 데이터를 저장하는 방법을 설명하겠습니다. Flutter 프로젝트에서 SQLite를 사용하기 위해 sqflite 패키지를 사용합니다. 이 패키지를 사용하여 데이터베이스를 생성하고, 할 일 데이터를 저장하고, 읽고, 업데이트하고, 삭제할 수 있습니다.
프로젝트 설정
1. pubspec.yaml 파일에 sqflite와 path 패키지를 추가합니다.
dependencies:
flutter:
sdk: flutter
sqflite: ^2.0.0+4
path: ^1.8.0
디렉토리 및 파일 구조
lib/
main.dart
models/
todo.dart
screens/
todo_list_screen.dart
edit_todo_screen.dart
services/
database_helper.dart
providers/
todo_provider.dart
1. 모델 정의
models/todo.dartㅣㅇve
class Todo {
String id;
String title;
bool isDone;
Todo({
required this.id,
required this.title,
this.isDone = false,
});
// 데이터베이스에서 읽은 데이터를 객체로 변환
factory Todo.fromMap(Map<String, dynamic> json) => new Todo(
id: json["id"],
title: json["title"],
isDone: json["isDone"] == 1,
);
// 객체 데이터를 데이터베이스에 저장할 수 있는 형태로 변환
Map<String, dynamic> toMap() => {
"id": id,
"title": title,
"isDone": isDone ? 1 : 0,
};
}
2. 데이터베이스 헬퍼 클래스 작성
services/database_helper.dart
import 'dart:async';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import '../models/todo.dart';
class DatabaseHelper {
static final DatabaseHelper _instance = DatabaseHelper._internal();
factory DatabaseHelper() => _instance;
static Database? _database;
DatabaseHelper._internal();
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
Future<Database> _initDatabase() async {
String path = join(await getDatabasesPath(), 'todo_database.db');
return await openDatabase(
path,
version: 1,
onCreate: _onCreate,
);
}
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE todos(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
isDone INTEGER
)
''');
}
Future<List<Todo>> getTodos() async {
final db = await database;
var res = await db.query('todos');
List<Todo> list =
res.isNotEmpty ? res.map((c) => Todo.fromMap(c)).toList() : [];
return list;
}
Future<int> insertTodo(Todo todo) async {
final db = await database;
return await db.insert('todos', todo.toMap());
}
Future<int> updateTodo(Todo todo) async {
final db = await database;
return await db.update(
'todos',
todo.toMap(),
where: 'id = ?',
whereArgs: [todo.id],
);
}
Future<int> deleteTodo(int id) async {
final db = await database;
return await db.delete(
'todos',
where: 'id = ?',
whereArgs: [id],
);
}
}
3. 프로바이더 설정
providers/todo_provider.dart
import 'package:flutter/material.dart';
import '../models/todo.dart';
import '../services/database_helper.dart';
class TodoProvider with ChangeNotifier {
List<Todo> _todos = [];
List<Todo> get todos => _todos;
Future<void> loadTodos() async {
_todos = await DatabaseHelper().getTodos();
notifyListeners();
}
Future<void> addTodo(Todo todo) async {
await DatabaseHelper().insertTodo(todo);
await loadTodos();
}
Future<void> updateTodo(Todo todo) async {
await DatabaseHelper().updateTodo(todo);
await loadTodos();
}
Future<void> removeTodo(int id) async {
await DatabaseHelper().deleteTodo(id);
await loadTodos();
}
}
4. UI 작성
screens/todo_list_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/todo.dart';
import '../providers/todo_provider.dart';
import 'edit_todo_screen.dart';
class TodoListScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('To-Do List'),
),
body: FutureBuilder(
future: Provider.of<TodoProvider>(context, listen: false).loadTodos(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Consumer<TodoProvider>(
builder: (context, todoProvider, child) {
return ListView.builder(
itemCount: todoProvider.todos.length,
itemBuilder: (ctx, i) => ListTile(
title: Text(todoProvider.todos[i].title),
trailing: Checkbox(
value: todoProvider.todos[i].isDone,
onChanged: (_) {
todoProvider.updateTodo(
Todo(
id: todoProvider.todos[i].id,
title: todoProvider.todos[i].title,
isDone: !todoProvider.todos[i].isDone,
),
);
},
),
onLongPress: () {
todoProvider.removeTodo(todoProvider.todos[i].id!);
},
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => EditTodoScreen(todo: todoProvider.todos[i]),
),
);
},
),
);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (ctx) {
TextEditingController controller = TextEditingController();
return AlertDialog(
title: Text('Add Todo'),
content: TextField(
controller: controller,
decoration: InputDecoration(labelText: 'Title'),
),
actions: [
TextButton(
onPressed: () {
if (controller.text.isNotEmpty) {
final newTodo = Todo(
title: controller.text,
);
Provider.of<TodoProvider>(context, listen: false).addTodo(newTodo);
Navigator.of(ctx).pop();
}
},
child: Text('Add'),
),
],
);
},
);
},
child: Icon(Icons.add),
),
);
}
}
screens/edit_todo_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/todo.dart';
import '../providers/todo_provider.dart';
class EditTodoScreen extends StatelessWidget {
final Todo todo;
EditTodoScreen({required this.todo});
@override
Widget build(BuildContext context) {
TextEditingController titleController = TextEditingController(text: todo.title);
return Scaffold(
appBar: AppBar(
title: Text('Edit Todo'),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: titleController,
decoration: InputDecoration(labelText: 'Title'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (titleController.text.isNotEmpty) {
final updatedTodo = Todo(
id: todo.id,
title: titleController.text,
isDone: todo.isDone,
);
Provider.of<TodoProvider>(context, listen: false).updateTodo(updatedTodo);
Navigator.of(context).pop();
}
},
child: Text('Update'),
),
],
),
),
);
}
}
5. 메인 파일 설정
main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'screens/todo_list_screen.dart';
import 'providers/todo_provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => TodoProvider()),
],
child: MaterialApp(
title: 'To-Do App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TodoListScreen(),
),
);
}
}
요약
1. `sqflite`와 `path` 패키지를 사용하여 SQLite 데이터베이스를 설정합니다.
2. 데이터 모델(`Todo`)을 정의합니다.
3. 데이터베이스 헬퍼 클래스(`DatabaseHelper`)를 작성하여 CRUD 작업을 수행합니다.
4. 프로바이더(`TodoProvider`)를 설정하여 데이터베이스와 UI 간의 상태를 관리합니다.
5. UI를 작성하여 할 일 목록을 표시하고, 할 일을 추가, 수정, 삭제할 수 있는 기능을 제공합니다.
6. 메인 파일에서 MultiProvider를 설정하여 앱을 실행합니다.
반응형
'프론트엔드 > Flutter' 카테고리의 다른 글
flutter future 키워드 및 aysnc await 를 통한 비동기처리 (0) | 2024.07.28 |
---|---|
flutter firestore 시작하기 - firebase 데이터베이스 (0) | 2024.07.25 |
flutter에서 바텀 네비게이션 바(Bottom Navigation Bar) (0) | 2024.07.24 |
flutter 주요 버튼 위젯 모음 (1) | 2024.07.24 |
flutter 입력 위젯 모음 (0) | 2024.07.24 |