teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

1

ソースコードを追記しました。

2021/05/26 02:37

投稿

momiji0210
momiji0210

スコア60

title CHANGED
File without changes
body CHANGED
@@ -19,6 +19,29 @@
19
19
 
20
20
  [https://qiita.com/mamoru_takami/items/f53aebd97fb1140d122a]
21
21
  ```Dart
22
+ import 'package:flutter/material.dart';
23
+
24
+ void main() => runApp(MyApp());
25
+
26
+ class Todo {
27
+ final String title;
28
+ final String description;
29
+ Todo({@required this.title, @required this.description})
30
+ : assert(title != null),
31
+ assert(description != null);
32
+ }
33
+
34
+ class MyApp extends StatelessWidget {
35
+ @override
36
+ Widget build(BuildContext context) {
37
+ return MaterialApp(
38
+ debugShowCheckedModeBanner: false, // Debug文言の削除
39
+ title: 'Navigation',
40
+ home: ListScreen2(title: 'List'),
41
+ );
42
+ }
43
+ }
44
+
22
45
  class Model {
23
46
  String title;
24
47
  String subTitle;
@@ -29,75 +52,245 @@
29
52
  @required this.subTitle,
30
53
  @required this.key,
31
54
  });
55
+ }
32
56
 
57
+ class ListScreen2 extends StatefulWidget {
58
+ ListScreen2({Key key, this.title}) : super(key: key);
59
+
60
+ final String title;
61
+
62
+ @override
63
+ _ListScreenState2 createState() => _ListScreenState2();
33
64
  }
34
65
 
35
- // TopScreen一部
36
- onTap: () async {
37
- var result = await Navigator.push(
38
- context,
39
- MaterialPageRoute(
40
- builder: (context) => NextScreen(model: model)));
66
+ class _ListScreenState2 extends State<ListScreen2> {
41
- //print(result);
42
- setState(() {
43
- model = result;
44
- print('set state ' + model.title);
67
+ List<Model> modelList;
45
- });
46
- },
47
68
 
69
+ @override
48
- // NextScreen一部
70
+ // 起動時に初期化
71
+ void initState() {
72
+ super.initState();
49
73
 
50
- // 起動時に初期化
51
- void initState() {
74
+ modelList = [];
52
- super.initState();
75
+ List<String> titleList = ["Title A", "Title B", "Title C"];
53
-
76
+ List<String> subTitleList = ["SubTitle A", "SubTitle B", "SubTitle C"];
77
+
54
- // _initModel = model;
78
+ for (int i = 0; i < 3; i++) {
55
- // これだと同じものを参照している?っぽい挙動
56
-
57
- _initModel = Model(
79
+ Model model = Model(
58
- title: widget._model.title,
80
+ title: titleList[i],
59
- subTitle: widget._model.subTitle,
81
+ subTitle: subTitleList[i],
60
- key: widget._model.key,
82
+ key: i.toString(),
61
- );
83
+ );
84
+ modelList.add(model);
85
+ }
86
+ }
87
+
88
+ // リスト項目となる削除可能なウィジェットを作成
89
+ Widget buildItem(Model model, int index) {
90
+ return Dismissible(
91
+ key: Key('${model.key}'), // 項目が特定できるよう固有の文字列をキーとする
92
+ background: Container(
93
+ padding: EdgeInsets.only(
94
+ right: 48,
95
+ ),
96
+ alignment: AlignmentDirectional.centerEnd,
97
+ color: Colors.red,
98
+ child: Icon(
99
+ Icons.delete,
100
+ color: Colors.white,
101
+ ),
102
+ ), // スワイプしているアイテムの背景色
103
+ direction: DismissDirection.endToStart,
104
+ confirmDismiss: (direction) async {
105
+ // 削除するか確認する
106
+ return await showDialog(
107
+ context: context,
108
+ builder: (BuildContext context) {
109
+ return AlertDialog(
110
+ title: Text('確認ダイアログ'),
111
+ content: Text('本当に削除しますか?'),
112
+ actions: <Widget>[
113
+ TextButton(
114
+ onPressed: () => Navigator.of(context).pop(false),
115
+ child: Text('CANCEL'),
116
+ ),
117
+ TextButton(
118
+ onPressed: () => Navigator.of(context).pop(true),
119
+ child:
120
+ Text('DELETE', style: TextStyle(color: Colors.red))),
121
+ ],
122
+ );
123
+ },
124
+ );
125
+ },
126
+ onDismissed: (direction) {
127
+ // 削除時の処理
128
+ setState(() {
129
+ modelList.remove(model);
130
+ });
131
+ },
132
+ // 各項目のレイアウト
133
+ child: Card(
134
+ child: ListTile(
135
+ tileColor: Theme.of(context).cardColor,
136
+ title: Text('${model.title}',
137
+ style: TextStyle(
138
+ fontWeight: FontWeight.bold, fontSize: 20, height: 1.2)),
139
+ subtitle: Text('${model.key} ${model.subTitle}'),
140
+ onTap: () async {
141
+ var result = await Navigator.push(
142
+ context,
143
+ MaterialPageRoute(
144
+ builder: (context) => NextScreen2(model: model)));
145
+ //print(result);
146
+ setState(() {
147
+ if (result != null) {
148
+ model = result;
149
+ print('set state ' + model.title);
150
+ }
151
+ });
152
+ },
153
+ )));
154
+ }
155
+
156
+ @override
157
+ Widget build(BuildContext context) {
158
+ return Scaffold(
159
+ appBar: AppBar(
160
+ title: Text(widget.title),
161
+ ),
162
+ body: Container(
163
+ child: ReorderableListView(
164
+ onReorder: (int oldIndex, int newIndex) {
165
+ if (newIndex > oldIndex) {
166
+ // 元々下にあった要素が上にずれるため一つ分後退させる
167
+ newIndex -= 1;
168
+ }
169
+
170
+ // 並び替え処理
171
+ Model model = modelList[oldIndex];
172
+ setState(() {
173
+ modelList.removeAt(oldIndex);
174
+ modelList.insert(newIndex, model);
175
+ });
176
+ },
177
+ padding: EdgeInsets.only(top: 4),
178
+ children: modelList
179
+ .asMap()
180
+ .map((i, item) => MapEntry(i, buildItem(item, i)))
181
+ .values
182
+ .toList())
183
+ //],
184
+ ));
185
+ }
62
186
  }
63
-
64
- return WillPopScope(
65
- onWillPop: () {
66
- print('onWillPop');
67
- Navigator.of(context).pop(_initModel);
68
- return Future.value(false);
69
- },
70
-
71
- child: Column(
72
- children: [
73
187
 
74
- ElevatedButton(
75
- child: Text('確定'),
76
- onPressed: () {
77
- // TODO: 新規登録
78
- // 前の画面に戻る
79
- print('確定');
80
- if (Navigator.of(context).canPop()) {
81
- Navigator.of(context).pop(widget._model);
82
- }
83
- },
84
- ),
85
-
86
- ElevatedButton(
87
- child: Text('キャンセル'),
88
- onPressed: () {
89
- print('キャンセル');
90
- // 前の画面に戻る
91
- widget._model = _initModel;
92
- if (Navigator.of(context).canPop()) {
93
- Navigator.of(context).pop(_initModel);
94
- }
95
- },
96
- style: ElevatedButton.styleFrom(
97
- primary: Colors.grey[200],
98
- onPrimary: Colors.black45,
99
- ),
100
- ),
101
- ]
102
- )
188
+ ///////////
189
+
190
+ class NextScreen2 extends StatefulWidget {
191
+ Model _model;
192
+
193
+ NextScreen2({Key key, @required Model model})
194
+ : assert(model != null),
195
+ this._model = model,
196
+ super(key: key);
197
+
198
+ @override
199
+ _NextScreenState2 createState() => _NextScreenState2();
200
+ }
201
+
202
+ class _NextScreenState2 extends State<NextScreen2> {
203
+ // 起動時に初期化
204
+ Model _initModel;
205
+
206
+ void initState() {
207
+ super.initState();
208
+
209
+ _initModel = Model(
210
+ title: widget._model.title,
211
+ subTitle: widget._model.subTitle,
212
+ key: widget._model.key,
213
+ );
214
+ }
215
+
216
+ @override
217
+ Widget build(BuildContext context) {
218
+ return WillPopScope(
219
+ onWillPop: () {
220
+ print('onWillPop');
221
+ Navigator.of(context).pop(_initModel);
222
+ return Future.value(false);
223
+ },
224
+ child: Scaffold(
225
+ appBar: AppBar(
226
+ title: Text('Edit'),
227
+ ),
228
+ body: Container(
229
+ padding: EdgeInsets.all(20),
230
+ child: Column(
231
+ mainAxisAlignment: MainAxisAlignment.start,
232
+ children: <Widget>[
233
+ // タイトル
234
+ TextField(
235
+ controller: TextEditingController()
236
+ ..text = widget._model.title,
237
+ decoration: InputDecoration(
238
+ hintText: 'タイトル',
239
+ hintStyle: TextStyle(
240
+ color: Colors.black26,
241
+ ),
242
+ ),
243
+ onChanged: (text) {
244
+ widget._model.title = text;
245
+ },
246
+ ),
247
+
248
+ // 登録ボタン
249
+ Container(
250
+ //padding: EdgeInsets.all(_PADDING_SIZE),
251
+ padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
252
+ width: double.infinity, // 横幅いっぱいに広げる
253
+ height: 60,
254
+ child: ElevatedButton(
255
+ child: Text('確定'),
256
+ onPressed: () {
257
+ // TODO: 新規登録
258
+ // 前の画面に戻る
259
+ print('確定');
260
+ if (Navigator.of(context).canPop()) {
261
+ Navigator.of(context).pop(widget._model);
262
+ }
263
+ },
264
+ ),
265
+ ),
266
+
267
+ // キャンセルボタン
268
+ Container(
269
+ //padding: EdgeInsets.all(_PADDING_SIZE),
270
+ padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
271
+ width: double.infinity, // 横幅いっぱいに広げる
272
+ height: 60,
273
+ child: ElevatedButton(
274
+ child: Text('キャンセル'),
275
+ onPressed: () {
276
+ print('キャンセル');
277
+ // 前の画面に戻る
278
+ widget._model = _initModel;
279
+ if (Navigator.of(context).canPop()) {
280
+ Navigator.of(context).pop(null);
281
+ }
282
+ },
283
+ style: ElevatedButton.styleFrom(
284
+ primary: Colors.grey[200],
285
+ onPrimary: Colors.black45,
286
+ ),
287
+ ),
288
+ ),
289
+ ],
290
+ ),
291
+ ),
292
+ ));
293
+ }
294
+ }
295
+
103
296
  ```