回答編集履歴

3

コードの貼り間違え...

2021/05/26 08:15

投稿

popobot
popobot

スコア6586

test CHANGED
@@ -394,6 +394,8 @@
394
394
 
395
395
  Model _initModel;
396
396
 
397
+ TextEditingController _controller;
398
+
397
399
 
398
400
 
399
401
  void initState() {
@@ -412,6 +414,12 @@
412
414
 
413
415
  );
414
416
 
417
+
418
+
419
+ _controller = TextEditingController();
420
+
421
+ _controller.text = widget._model.title;
422
+
415
423
  }
416
424
 
417
425
 
@@ -454,9 +462,7 @@
454
462
 
455
463
  TextField(
456
464
 
457
- controller: TextEditingController()
465
+ controller: _controller,
458
-
459
- ..text = widget._model.title,
460
466
 
461
467
  decoration: InputDecoration(
462
468
 
@@ -470,12 +476,6 @@
470
476
 
471
477
  ),
472
478
 
473
- onChanged: (text) {
474
-
475
- widget._model.title = text;
476
-
477
- },
478
-
479
479
  ),
480
480
 
481
481
 
@@ -504,9 +504,11 @@
504
504
 
505
505
  print('確定');
506
506
 
507
+ widget._model.title = _controller.text;
508
+
507
509
  if (Navigator.of(context).canPop()) {
508
510
 
509
- Navigator.of(context).pop(widget._model);
511
+ Navigator.of(context).pop();
510
512
 
511
513
  }
512
514
 
@@ -544,7 +546,7 @@
544
546
 
545
547
  if (Navigator.of(context).canPop()) {
546
548
 
547
- Navigator.of(context).pop(null);
549
+ Navigator.of(context).pop();
548
550
 
549
551
  }
550
552
 

2

注記を追加

2021/05/26 08:15

投稿

popobot
popobot

スコア6586

test CHANGED
@@ -575,3 +575,9 @@
575
575
  }
576
576
 
577
577
  ```
578
+
579
+
580
+
581
+ この実装なら pop() で値を返す必要もないです
582
+
583
+ もし pop() で値を返すような実装にしたいなら、NectScreenに渡す際にモデルを生成し直せば、それでも実現できると思います

1

追記

2021/05/26 04:03

投稿

popobot
popobot

スコア6586

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