Flutter - пользовательский интерфейс не обновляется правильно при удалении элемента - PullRequest
2 голосов
/ 23 мая 2019

Я пытаюсь создать страницу, на которой пользователи могут добавлять и удалять элементы из списка.Я борюсь с проблемой.Когда я удаляю элемент, модель обновляется корректно, а пользовательский интерфейс обновляется, но неправильно: удаляется только последний элемент списка.

Я использую Flutter 1.5.4.

Я уже использовал более простые элементы для списка, и я попытался создать новый проект только с этой страницей, чтобы удалить все возможные проблемы, но он все еще не работает правильно.

Я также попытался использовать столбецвместо списка, но результат всегда один и тот же.

main.dart:

import 'package:flutter/material.dart';
import './widget.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Hello'),
        ),
        body: Center(
          child: SectionWidget(),
        ),
      ),
    );
  }
}

widget.dart:

import 'package:flutter/material.dart';

class SectionWidget extends StatefulWidget {
  _SectionWidgetState createState() => new _SectionWidgetState();
}

class _SectionWidgetState extends State<SectionWidget> {
  List<String> _items = List<String>();

  @override
  Widget build(BuildContext context) {
    List<Widget> children = [
      ListTile(
          title: Text(
            "Strings",
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
          trailing: IconButton(
            icon: Icon(Icons.add_circle),
            onPressed: () => setState(() {
                  _items.add('item ${_items.length}');
                  print("Adding "+ _items.last);
                }),
          ),
        ),
    ];

    children.addAll(_buildForms());


    return ListView(
      children: children,
    );
  }

  List<Widget> _buildForms() {
    List<Widget> forms = new List<Widget>();
    print("Strings:" + _items.toString());
    for (String item in _items) {
      forms.add(
        ListTile(
          leading: Icon(Icons.person),
          title: TextFormField(
            initialValue: item,
          ),
          trailing: IconButton(
            icon: Icon(Icons.delete),
            onPressed: () => setState(() {
                  print("Removing $item");
                  _items.remove(item);
                }),
          ),
        ),
      );
    }
    return forms;
  }
}

Если я добавлю 4 элемента всписок и затем удалить «элемент 1», это вывод на консоль:

I/flutter ( 4192): Strings:[]
I/flutter ( 4192): Adding item 0
I/flutter ( 4192): Strings:[item 0]
I/flutter ( 4192): Adding item 1
I/flutter ( 4192): Strings:[item 0, item 1]
I/flutter ( 4192): Adding item 2
I/flutter ( 4192): Strings:[item 0, item 1, item 2]
I/flutter ( 4192): Adding item 3
I/flutter ( 4192): Strings:[item 0, item 1, item 2, item 3]
I/flutter ( 4192): Removing item 1
I/flutter ( 4192): Strings:[item 0, item 2, item 3]

Это правильно, так как «элемент 1» был удален из списка, но если я смотрю на пользовательский интерфейс,вот что я получаю:

enter image description here

Количество элементов в списке правильное, модель правильная, но показанные элементы неправильные.

Как это исправить?Я что-то не так делаю или это ошибка Флаттера?

Ответы [ 4 ]

0 голосов
/ 23 мая 2019

Причиной удаления необновления удаленного элемента является то, что второй виджет является виджетом с состоянием, в некоторых случаях требуется принудительный рендеринг

используйте этот код для перезагрузки представления путем переопределения метода didUpdateWidget

 @override
  void didUpdateWidget(LoadImageFromPathAsync oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget != widget) {
        setState(() {});
    }
  }
0 голосов
/ 23 мая 2019

Ваше состояние виджета содержит только список строк.Когда вы удаляете один из них и виджет перестраивается, Flutter знает, что ваш ListView содержит на один меньше дочерний виджет, поэтому он удаляет последний и перестраивает другие.

Подвох в том, что вы 'Использование initialValue для установки текста на TextFormFields - весь смысл initialValue в том, что он не изменит текст на поле, даже если вы измените его - у TextFormField может быть только 1 начальное значениеи это тот, который вы устанавливаете изначально.

Если вы хотите, чтобы текст изменился, вам нужно использовать TextEditingController.В приведенном выше примере простая замена initialValue: item на controller: TextEditingController(text: item) должна исправить это.В реальном приложении вы, вероятно, захотите хранить контроллеры в состоянии виджета, чтобы введенные пользователем значения сохранялись при перестроениях.

0 голосов
/ 23 мая 2019

Как я понимаю, функция setState обновляет только данные виджета, а не создает виджет заново. В вашем коде вы используете initialValue, чтобы установить текст по умолчанию для TextField. Этот параметр используется только при создании TextField. Поэтому, когда вы удаляете элемент, приложение будет обновлять виджет в зависимости от длины _item (в этом случае оставьте 3 первых и удалите последний). initialValue не имеет смысла в настоящее время, потому что TextField не создается, а используется повторно.

Чтобы решить эту проблему, вы можете использовать TextEditingController для установки текста вместо initialVal

Сначала создайте список TextEditingController карты с _items

  List<TextEditingController> controllers = [];

Затем при добавлении элемента также создайте для него новый контроллер

onPressed: () => setState(() {
  _items.add('item ${_items.length}');
  controllers.add(TextEditingController(text:  "${_items.length}"));
  print("Adding "+ _items.last);
}),

Наконец, добавьте контроллер к TextField

TextFormField(
  controller: controllers[_items.indexOf(item)],
)

Ах, не забудьте удалить контроллер перед удалением элемента

controllers.removeAt(_items.indexOf(item));

Надеюсь, это поможет.

0 голосов
/ 23 мая 2019

Я думаю, что вам нужно создавать контроллеры для каждого текстового поля или использовать hintText

Scaffold(
      appBar: AppBar(
        title: Text('Hello'),
      ),
      body: ListView(
          children: <Widget>[
            ListTile(
              title: Text(
                'Strings',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              trailing: IconButton(
                icon: Icon(Icons.add_circle),
                onPressed: () => setState(() {
                      _items.add('item ${_items.length}');
                      print('Adding '+ _items.last);
                    }),
              ),
            ),
            ListView.builder(
              physics: BouncingScrollPhysics(),
              shrinkWrap: true,
              itemCount: _items.length,
              itemBuilder: (BuildContext context, int i){
                return ListTile(
                  leading: Icon(Icons.person),
                  title: TextFormField(
                    decoration: InputDecoration(
                      hintText: _items[i]
                    ),
                  ),
                  trailing: IconButton(
                    icon: Icon(Icons.delete),
                    onPressed: () => setState(() {
                          print('Removing ${_items[i]}');
                          _items.remove(_items[i]);
                        }),
                  ),
                );
              },
            )
          ]
        )
    );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...