質問編集履歴

1

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

2021/05/26 02:37

投稿

momiji0210
momiji0210

スコア60

test CHANGED
File without changes
test CHANGED
@@ -40,6 +40,52 @@
40
40
 
41
41
  ```Dart
42
42
 
43
+ import 'package:flutter/material.dart';
44
+
45
+
46
+
47
+ void main() => runApp(MyApp());
48
+
49
+
50
+
51
+ class Todo {
52
+
53
+ final String title;
54
+
55
+ final String description;
56
+
57
+ Todo({@required this.title, @required this.description})
58
+
59
+ : assert(title != null),
60
+
61
+ assert(description != null);
62
+
63
+ }
64
+
65
+
66
+
67
+ class MyApp extends StatelessWidget {
68
+
69
+ @override
70
+
71
+ Widget build(BuildContext context) {
72
+
73
+ return MaterialApp(
74
+
75
+ debugShowCheckedModeBanner: false, // Debug文言の削除
76
+
77
+ title: 'Navigation',
78
+
79
+ home: ListScreen2(title: 'List'),
80
+
81
+ );
82
+
83
+ }
84
+
85
+ }
86
+
87
+
88
+
43
89
  class Model {
44
90
 
45
91
  String title;
@@ -60,146 +106,486 @@
60
106
 
61
107
  });
62
108
 
63
-
64
-
65
- }
66
-
67
-
68
-
69
- // TopScreen一部
70
-
71
- onTap: () async {
72
-
73
- var result = await Navigator.push(
74
-
75
- context,
76
-
77
- MaterialPageRoute(
78
-
79
- builder: (context) => NextScreen(model: model)));
80
-
81
- //print(result);
82
-
83
- setState(() {
84
-
85
- model = result;
86
-
87
- print('set state ' + model.title);
88
-
89
- });
90
-
91
- },
92
-
93
-
94
-
95
- // NextScreen一部
96
-
97
-
98
-
99
- // 起動時に初期化
100
-
101
- void initState() {
102
-
103
- super.initState();
104
-
105
-
106
-
107
- // _initModel = model;
108
-
109
- // これだと同じものを参照している?っぽい挙動
110
-
111
-
112
-
113
- _initModel = Model(
114
-
115
- title: widget._model.title,
116
-
117
- subTitle: widget._model.subTitle,
118
-
119
- key: widget._model.key,
120
-
121
- );
122
-
123
- }
124
-
125
-
126
-
127
- return WillPopScope(
128
-
129
- onWillPop: () {
130
-
131
- print('onWillPop');
132
-
133
- Navigator.of(context).pop(_initModel);
134
-
135
- return Future.value(false);
136
-
137
- },
138
-
139
-
140
-
141
- child: Column(
142
-
143
- children: [
144
-
145
-
146
-
147
- ElevatedButton(
148
-
149
- child: Text('確定'),
150
-
151
- onPressed: () {
152
-
153
- // TODO: 新規登録
154
-
155
- // 前の画面に戻る
156
-
157
- print('確定');
158
-
159
- if (Navigator.of(context).canPop()) {
160
-
161
- Navigator.of(context).pop(widget._model);
162
-
163
- }
164
-
165
- },
166
-
167
- ),
168
-
169
-
170
-
171
- ElevatedButton(
172
-
173
- child: Text('キャンセル'),
174
-
175
- onPressed: () {
176
-
177
- print('キャンセル');
178
-
179
- // 前の画面に戻る
180
-
181
- widget._model = _initModel;
182
-
183
- if (Navigator.of(context).canPop()) {
184
-
185
- Navigator.of(context).pop(_initModel);
186
-
187
- }
188
-
189
- },
190
-
191
- style: ElevatedButton.styleFrom(
192
-
193
- primary: Colors.grey[200],
194
-
195
- onPrimary: Colors.black45,
196
-
197
- ),
198
-
199
- ),
200
-
201
- ]
202
-
203
- )
109
+ }
110
+
111
+
112
+
113
+ class ListScreen2 extends StatefulWidget {
114
+
115
+ ListScreen2({Key key, this.title}) : super(key: key);
116
+
117
+
118
+
119
+ final String title;
120
+
121
+
122
+
123
+ @override
124
+
125
+ _ListScreenState2 createState() => _ListScreenState2();
126
+
127
+ }
128
+
129
+
130
+
131
+ class _ListScreenState2 extends State<ListScreen2> {
132
+
133
+ List<Model> modelList;
134
+
135
+
136
+
137
+ @override
138
+
139
+ // 起動時に初期化
140
+
141
+ void initState() {
142
+
143
+ super.initState();
144
+
145
+
146
+
147
+ modelList = [];
148
+
149
+ List<String> titleList = ["Title A", "Title B", "Title C"];
150
+
151
+ List<String> subTitleList = ["SubTitle A", "SubTitle B", "SubTitle C"];
152
+
153
+
154
+
155
+ for (int i = 0; i < 3; i++) {
156
+
157
+ Model model = Model(
158
+
159
+ title: titleList[i],
160
+
161
+ subTitle: subTitleList[i],
162
+
163
+ key: i.toString(),
164
+
165
+ );
166
+
167
+ modelList.add(model);
168
+
169
+ }
170
+
171
+ }
172
+
173
+
174
+
175
+ // リスト項目となる削除可能なウィジェットを作成
176
+
177
+ Widget buildItem(Model model, int index) {
178
+
179
+ return Dismissible(
180
+
181
+ key: Key('${model.key}'), // 項目が特定できるよう固有の文字列をキーとする
182
+
183
+ background: Container(
184
+
185
+ padding: EdgeInsets.only(
186
+
187
+ right: 48,
188
+
189
+ ),
190
+
191
+ alignment: AlignmentDirectional.centerEnd,
192
+
193
+ color: Colors.red,
194
+
195
+ child: Icon(
196
+
197
+ Icons.delete,
198
+
199
+ color: Colors.white,
200
+
201
+ ),
202
+
203
+ ), // スワイプしているアイテムの背景色
204
+
205
+ direction: DismissDirection.endToStart,
206
+
207
+ confirmDismiss: (direction) async {
208
+
209
+ // 削除するか確認する
210
+
211
+ return await showDialog(
212
+
213
+ context: context,
214
+
215
+ builder: (BuildContext context) {
216
+
217
+ return AlertDialog(
218
+
219
+ title: Text('確認ダイアログ'),
220
+
221
+ content: Text('本当に削除しますか?'),
222
+
223
+ actions: <Widget>[
224
+
225
+ TextButton(
226
+
227
+ onPressed: () => Navigator.of(context).pop(false),
228
+
229
+ child: Text('CANCEL'),
230
+
231
+ ),
232
+
233
+ TextButton(
234
+
235
+ onPressed: () => Navigator.of(context).pop(true),
236
+
237
+ child:
238
+
239
+ Text('DELETE', style: TextStyle(color: Colors.red))),
240
+
241
+ ],
242
+
243
+ );
244
+
245
+ },
246
+
247
+ );
248
+
249
+ },
250
+
251
+ onDismissed: (direction) {
252
+
253
+ // 削除時の処理
254
+
255
+ setState(() {
256
+
257
+ modelList.remove(model);
258
+
259
+ });
260
+
261
+ },
262
+
263
+ // 各項目のレイアウト
264
+
265
+ child: Card(
266
+
267
+ child: ListTile(
268
+
269
+ tileColor: Theme.of(context).cardColor,
270
+
271
+ title: Text('${model.title}',
272
+
273
+ style: TextStyle(
274
+
275
+ fontWeight: FontWeight.bold, fontSize: 20, height: 1.2)),
276
+
277
+ subtitle: Text('${model.key} ${model.subTitle}'),
278
+
279
+ onTap: () async {
280
+
281
+ var result = await Navigator.push(
282
+
283
+ context,
284
+
285
+ MaterialPageRoute(
286
+
287
+ builder: (context) => NextScreen2(model: model)));
288
+
289
+ //print(result);
290
+
291
+ setState(() {
292
+
293
+ if (result != null) {
294
+
295
+ model = result;
296
+
297
+ print('set state ' + model.title);
298
+
299
+ }
300
+
301
+ });
302
+
303
+ },
304
+
305
+ )));
306
+
307
+ }
308
+
309
+
310
+
311
+ @override
312
+
313
+ Widget build(BuildContext context) {
314
+
315
+ return Scaffold(
316
+
317
+ appBar: AppBar(
318
+
319
+ title: Text(widget.title),
320
+
321
+ ),
322
+
323
+ body: Container(
324
+
325
+ child: ReorderableListView(
326
+
327
+ onReorder: (int oldIndex, int newIndex) {
328
+
329
+ if (newIndex > oldIndex) {
330
+
331
+ // 元々下にあった要素が上にずれるため一つ分後退させる
332
+
333
+ newIndex -= 1;
334
+
335
+ }
336
+
337
+
338
+
339
+ // 並び替え処理
340
+
341
+ Model model = modelList[oldIndex];
342
+
343
+ setState(() {
344
+
345
+ modelList.removeAt(oldIndex);
346
+
347
+ modelList.insert(newIndex, model);
348
+
349
+ });
350
+
351
+ },
352
+
353
+ padding: EdgeInsets.only(top: 4),
354
+
355
+ children: modelList
356
+
357
+ .asMap()
358
+
359
+ .map((i, item) => MapEntry(i, buildItem(item, i)))
360
+
361
+ .values
362
+
363
+ .toList())
364
+
365
+ //],
366
+
367
+ ));
368
+
369
+ }
370
+
371
+ }
372
+
373
+
374
+
375
+ ///////////
376
+
377
+
378
+
379
+ class NextScreen2 extends StatefulWidget {
380
+
381
+ Model _model;
382
+
383
+
384
+
385
+ NextScreen2({Key key, @required Model model})
386
+
387
+ : assert(model != null),
388
+
389
+ this._model = model,
390
+
391
+ super(key: key);
392
+
393
+
394
+
395
+ @override
396
+
397
+ _NextScreenState2 createState() => _NextScreenState2();
398
+
399
+ }
400
+
401
+
402
+
403
+ class _NextScreenState2 extends State<NextScreen2> {
404
+
405
+ // 起動時に初期化
406
+
407
+ Model _initModel;
408
+
409
+
410
+
411
+ void initState() {
412
+
413
+ super.initState();
414
+
415
+
416
+
417
+ _initModel = Model(
418
+
419
+ title: widget._model.title,
420
+
421
+ subTitle: widget._model.subTitle,
422
+
423
+ key: widget._model.key,
424
+
425
+ );
426
+
427
+ }
428
+
429
+
430
+
431
+ @override
432
+
433
+ Widget build(BuildContext context) {
434
+
435
+ return WillPopScope(
436
+
437
+ onWillPop: () {
438
+
439
+ print('onWillPop');
440
+
441
+ Navigator.of(context).pop(_initModel);
442
+
443
+ return Future.value(false);
444
+
445
+ },
446
+
447
+ child: Scaffold(
448
+
449
+ appBar: AppBar(
450
+
451
+ title: Text('Edit'),
452
+
453
+ ),
454
+
455
+ body: Container(
456
+
457
+ padding: EdgeInsets.all(20),
458
+
459
+ child: Column(
460
+
461
+ mainAxisAlignment: MainAxisAlignment.start,
462
+
463
+ children: <Widget>[
464
+
465
+ // タイトル
466
+
467
+ TextField(
468
+
469
+ controller: TextEditingController()
470
+
471
+ ..text = widget._model.title,
472
+
473
+ decoration: InputDecoration(
474
+
475
+ hintText: 'タイトル',
476
+
477
+ hintStyle: TextStyle(
478
+
479
+ color: Colors.black26,
480
+
481
+ ),
482
+
483
+ ),
484
+
485
+ onChanged: (text) {
486
+
487
+ widget._model.title = text;
488
+
489
+ },
490
+
491
+ ),
492
+
493
+
494
+
495
+ // 登録ボタン
496
+
497
+ Container(
498
+
499
+ //padding: EdgeInsets.all(_PADDING_SIZE),
500
+
501
+ padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
502
+
503
+ width: double.infinity, // 横幅いっぱいに広げる
504
+
505
+ height: 60,
506
+
507
+ child: ElevatedButton(
508
+
509
+ child: Text('確定'),
510
+
511
+ onPressed: () {
512
+
513
+ // TODO: 新規登録
514
+
515
+ // 前の画面に戻る
516
+
517
+ print('確定');
518
+
519
+ if (Navigator.of(context).canPop()) {
520
+
521
+ Navigator.of(context).pop(widget._model);
522
+
523
+ }
524
+
525
+ },
526
+
527
+ ),
528
+
529
+ ),
530
+
531
+
532
+
533
+ // キャンセルボタン
534
+
535
+ Container(
536
+
537
+ //padding: EdgeInsets.all(_PADDING_SIZE),
538
+
539
+ padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
540
+
541
+ width: double.infinity, // 横幅いっぱいに広げる
542
+
543
+ height: 60,
544
+
545
+ child: ElevatedButton(
546
+
547
+ child: Text('キャンセル'),
548
+
549
+ onPressed: () {
550
+
551
+ print('キャンセル');
552
+
553
+ // 前の画面に戻る
554
+
555
+ widget._model = _initModel;
556
+
557
+ if (Navigator.of(context).canPop()) {
558
+
559
+ Navigator.of(context).pop(null);
560
+
561
+ }
562
+
563
+ },
564
+
565
+ style: ElevatedButton.styleFrom(
566
+
567
+ primary: Colors.grey[200],
568
+
569
+ onPrimary: Colors.black45,
570
+
571
+ ),
572
+
573
+ ),
574
+
575
+ ),
576
+
577
+ ],
578
+
579
+ ),
580
+
581
+ ),
582
+
583
+ ));
584
+
585
+ }
586
+
587
+ }
588
+
589
+
204
590
 
205
591
  ```