Виджет Flutter Data Monitor автоматически обновляет ваш пользовательский интерфейс

Flutter

В разработке мы, вероятно, выполним это требование:

Каждый кружок здесь — одни и те же данные.

Теперь, когда данные этого круга были изменены, нам нужно обновить все данные на этой странице, не слишком ли это хлопотно?

Flutter учитывает это для нас.

ValueListenableBuilder

Глядя на имя, мы также можем видеть, для чего предназначен этот элемент управления, конструктор прослушиваемого значения.

Тогда давайте как обычно посмотрим официальную документацию:

A widget whose content stays synced with a ValueListenable.

Given a ValueListenable<T> and a builder which builds widgets from concrete values of T, this class will automatically register itself as a listener of the ValueListenable and call the builder with updated values when the value changes.

Элемент управления, который выравнивает содержимое с ValueListenable.

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

сказав так многоValueListenable, что это такое?

Нажмите, чтобы увидеть:

// 用于公开值的可侦听子类的接口。
An interface for subclasses of Listenable that expose a value.

// 这个接口由ValueNotifier和Animation实现,并且允许其他API交替接受这些实现中的任何一个。
This interface is implemented by ValueNotifier<T> and Animation<T>, and allows other APIs to accept either of those implementations interchangeably.

То есть этот класс реализован ValueNotifier и Animation, и мы можем понять, что они делают из названия.

Один — это значение, а другой — анимация.

Официальная демоверсия

Давайте посмотрим на официальную демоверсию, чтобы подтвердить, как ее использовать:

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final ValueNotifier<int> _counter = ValueNotifier<int>(0);
  final Widget goodJob = const Text('Good job!');
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title)
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('You have pushed the button this many times:'),
            ValueListenableBuilder(
              builder: (BuildContext context, int value, Widget child) {
								// 只有在更新计数器时才会调用此生成器。
                return Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    Text('$value'),
                    child,
                  ],
                );
              },
              valueListenable: _counter,
							// 如果child 的构建成本很高,并且不依赖于通知程序的值,则child参数非常有用。
              child: goodJob,
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.plus_one),
        // 点击的时候用 ValueNotifier 来更新值
        onPressed: () => _counter.value += 1,
      ),
    );
  }
}

Код относительно прост, просто добавьтеValueListenableBuilder.

Затем обновите значение при нажатии FAB.

Запустим программу и посмотрим, как она выглядит:

Официальный пример пишет всю информацию о контроле, но он не интуитивно понятен и не показывает мощности контрола.

Отображение пользовательской страницы ValueListenableBuilder

Я также написал небольшое демо:

код показывает, как показано ниже:

class _ValueListenableBuildPageState extends State<ValueListenableBuildPage> {
  
  ValueNotifier<Person> _valueListenable = ValueNotifier<Person>(
      Person(name: 'WAnimal', age: 18, head: 'images/bg.jpg'));
  Widget _contentWidget;
  
  @override
  void initState() {
    super.initState();
    _contentWidget =
        Padding(
          padding: const EdgeInsets.all(10.0),
          child: Text(
            '我是正文我是正文我是正文我是正文我是正文我是正文我是正文我是正文我是正文我是正文我是正文我是正文我是正文我是正文我是正文',
            style: TextStyle(fontSize: 16),
          ),
        );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ValueListenableBuildPage'),
      ),
      body: ValueListenableBuilder(
        valueListenable: _valueListenable,
        builder: (BuildContext context, Person value, Widget child) {
          return SingleChildScrollView(
            child: Column(
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.only(top: 18.0),
                  child: ClipOval(
                    child: Image.asset(
                      value.head,
                      fit: BoxFit.cover,
                      width: 100,
                      height: 100,
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(vertical: 8.0),
                  child: Text(
                    '${value.name}',
                    style: TextStyle(
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                      color: Colors.black,
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.only(bottom: 8.0),
                  child: Text(
                    'age:${value.age}',
                    style: TextStyle(
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                      color: Colors.black,
                    ),
                  ),
                ),
                ListView.builder(
                  shrinkWrap: true,
                  itemCount: 10,
                  physics: NeverScrollableScrollPhysics(),
                  itemBuilder: (context, index) {
                    return Column(
                      children: <Widget>[
                        Row(
                          children: <Widget>[
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: ClipOval(
                                child: Image.asset(
                                  value.head,
                                  fit: BoxFit.cover,
                                  width: 50,
                                  height: 50,
                                ),
                              ),
                            ),
                            Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: <Widget>[
                                Padding(
                                  padding:
                                  const EdgeInsets.symmetric(vertical: 4.0),
                                  child: Text(
                                    '${value.name}',
                                    style: TextStyle(
                                      fontSize: 18,
                                      fontWeight: FontWeight.bold,
                                      color: Colors.black,
                                    ),
                                  ),
                                ),
                                Text(
                                  'age: ${value.age}',
                                  style: TextStyle(
                                    fontSize: 16,
                                    color: Colors.black,
                                  ),
                                ),
                              ],
                            ),
                          ],
                        ),
                        child
                      ],
                    );
                  },
                )
              ],
            ),
          );
        },
        child: _contentWidget,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _valueListenable.value = Person(name: '91李先生', age: 24, head: 'images/bg.png');
        },
        child: Icon(Icons.refresh),
      ),
    );
  }
}

Согласно официальной демонстрации, элементы управления, которым не нужно отслеживать значение, помещаются в дочерний параметр после их инициализации в другом месте.

Итак, мы инициализировали _contentWidget в методе initState() как тело ListView.

Затем мы обертываем информацию о пользователе верхнего уровня в ValueListenableBuilder, а также информацию о пользователе статей, опубликованных пользователем ниже.

Наконец, измените объект Person в FAB для достижения цели обновления информации.

Пользовательское уведомление о значении

Увидев это, некоторые люди определенно скажут, что для меня невозможно обновить этот объект каждый раз. Я только хочу обновить одну из полей для достижения этого эффекта.

Нет проблем, старик, на этот раз это похоже наValueListenableКак упоминалось в документации, вам необходимо определить свой собственный ValueNotifier.

Это не сложно настроить, просто запомните один момент и назовите его там, где вам нужно изменитьnotifyListeners()Ничего страшного.

Пользовательский код PersonNotifier выглядит следующим образом:

class PersonNotifier extends ValueNotifier<Person>{
  PersonNotifier(Person value) : super(value);

  void changePersonName(String name){
    value.name = name;
    notifyListeners();
  }
}

Довольно простой код, определите метод для изменения имени, вызовите уведомление, и все в порядке.

Взгляните на эффект:

Суммировать

Здесь мы просто используем одну из функций ValueNotifier класса ValueListenableBuilder.

Вы также можете использовать Анимацию, методы использования аналогичны, вы можете изучить ее самостоятельно.

Flutter предоставляет нам множество очень удобных элементов управления.

Следите за мной, чтобы получать ежедневные обновления знаний о Flutter и Dart 🌝.

Полный код загружен на GitHub:GitHub.com/web1209/…