Zapp!はFlutterアプリをクラウド環境で開発できるサービスです。DartPadと違って、任意のFlutter/Dartパッケージをインストールできます。
そんなZapp!を使って、ニフクラ mobile backendのFlutter SDKを利用したデモアプリであるTodoアプリを体験できるようにしました。
アプリの概要
アプリは2画面で作られています。
Todo一覧画面
NCMBのデータストアからTodoを一覧取得、画面に表示します。
Todo編集画面
一覧画面でタップされたTodoを編集する画面です。新規登録でも同じ画面を使っています。
アプリの機能
データストアのCRUD操作(データの取得、新規作成、更新、削除)が体験できます。タスクのスワイプで削除が出ます。
データは自由に操作してもらって構いません。
アプリのURL
Todoアプリは下記のURLで試せます。
アプリのコード
アプリのコードは下記になります。
Zapp!は誰でも編集できるような気がするので、こちらに予備としてコードを全文残しておきます。
import 'package:flutter/material.dart';
import 'package:ncmb/ncmb.dart';
void main() {
// NCMBを初期化
NCMB('9170ffcb91da1bbe0eff808a967e12ce081ae9e3262ad3e5c3cac0d9e54ad941', '9e5014cd2d76a73b4596deffdc6ec4028cfc1373529325f8e71b7a6ed553157d');
// 最初に表示するWidget
runApp(MyTodoApp());
}
class MyTodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// 右上に表示される"debug"ラベルを消す
debugShowCheckedModeBanner: false,
// アプリ名
title: 'タスクアプリ',
theme: ThemeData(
// テーマカラー
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
// リスト一覧画面を表示
home: TodoListPage(),
);
}
}
// タスク一覧画面用Widget
class TodoListPage extends StatefulWidget {
@override
_TodoListPageState createState() => _TodoListPageState();
}
// タスク一覧画面用ステート
class _TodoListPageState extends State<TodoListPage> {
// Todoリストのデータ(初期値は空)
List<NCMBObject> todoList = [];
// 初期データをセットアップする処理
@override
void initState() {
super.initState();
getAllTask();
}
// NCMBから既存のTodoリストを取得する処理
void getAllTask() async {
// Todoクラス(DBで言うテーブル相当)を検索するクエリーオブジェクト
var query = NCMBQuery('Todo');
// データを取得
var items = await query.fetchAll();
// データを適用
setState(() {
todoList = items
.map((item) => item as NCMBObject)
.toList();
});
}
// 画面構築
@override
Widget build(BuildContext context) {
return Scaffold(
// 画面上部に表示するAppBar
appBar: AppBar(
title: Text('タスク一覧'),
// タスク追加用のアイコンを設置
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () async {
// 新しいTodoを取得
final NCMBObject item = await Navigator.of(context).push(
MaterialPageRoute(builder: (context) {
// タスクの追加、編集を行う画面への遷移
return TodoPage(
// 初期値としてNCMBObjectを渡す
todo: NCMBObject('Todo'),
);
}),
);
// レスポンスがあれば、リストに追加
// キャンセルされた場合は null が来る
if (item != null) {
setState(() {
todoList.add(item);
});
}
},
),
],
),
// データを元にListViewを作成
body: ListView.builder(
itemCount: todoList.length,
itemBuilder: (context, index) {
final item = todoList[index];
// スワイプで削除する機能
return Dismissible(
key: Key(item.get('objectId') as String),
child: Card(
child: ListTile(
title: Text(item.get('body') as String),
onTap: () async {
// タップした際には編集画面に遷移する
final NCMBObject obj = await Navigator.of(context).push(
MaterialPageRoute(builder: (context) {
return TodoPage(
todo: item,
);
}),
);
// 編集後のデータがあれば、リストを更新する
if (obj != null) {
setState(() {
todoList[index] = obj;
});
}
},
),
),
direction: DismissDirection.endToStart,
// スワイプした際に表示する削除ラベル
background: new Container(
padding: EdgeInsets.only(right: 20.0),
color: Colors.red.shade500,
child: new Align(
alignment: Alignment.centerRight,
child: new Text('削除',
textAlign: TextAlign.right,
style: new TextStyle(color: Colors.white)),
)),
// スワイプした際に処理
onDismissed: (direction) {
// スワイプされた要素をデータから削除する
setState(() {
todoList[index].delete();
todoList.removeAt(index);
});
// Snackbarを表示する
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('削除しました')));
},
);
},
),
);
}
}
// Todoを受け取るステートフルウィジェット
class TodoPage extends StatefulWidget {
TodoPage({
Key? key,
required this.todo,
}) : super(key: key);
final NCMBObject todo;
@override
_TodoPageState createState() => _TodoPageState();
}
// Todoの追加、または更新を行うウィジェット
class _TodoPageState extends State<TodoPage> {
// テキスト入力用
String? _text;
@override
Widget build(BuildContext context) {
// 画面表示用のラベル
final label = widget.todo.get('objectId') != null ? 'リスト更新' : 'リスト追加';
return Scaffold(
// 画面上部に表示するAppBar
appBar: AppBar(
title: Text(label),
actions: <Widget>[
// 新規保存、更新用のボタン
IconButton(
icon: Icon(Icons.save),
onPressed: () async {
// 保存処理
widget.todo.set('body', _text!);
await widget.todo.save();
// 前の画面に戻る
Navigator.of(context).pop(widget.todo);
},
),
],
),
body: Container(
// 余白を付ける
padding: EdgeInsets.all(64),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const SizedBox(height: 8),
// テキスト入力
TextFormField(
// 初期値の設定。デフォルト値は空文字
initialValue: (_text = widget.todo.getString('body', defaultValue: "")),
onChanged: (String value) {
_text = value;
},
),
],
),
),
);
}
}
コードの解説
このTodoアプリは【ハンズオン資料】NCMBのFlutter SDKを使ってTodoアプリを作る - Qiitaのコードを利用しています。Flutter 3.0.5に合わせて多少の修正が入っています。
まとめ
FlutterアプリでNCMBを使う際の参考として、ぜひご覧ください。データストアの基本的な使い方が分かるはずです。