Как задать значение по умолчанию для текстового поля при использовании блочного фреймворка

Я написал несколько простых приложений флаттера, которые используют виджеты / формы / текстовые поля с отслеживанием состояния для ввода и управления данными. Теперь я пытаюсь понять, как использовать BLoC и streambuilder для выполнения аналогичной работы. Но я не могу понять, как установить начальные значения для моих полей.

Я попытался создать простейший пример крошечного приложения с использованием блока. Это просто берет имя, которое вводится в TextField, и выводит его на следующую строку.

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Bloc Example',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage();

  String initialData = 'Fred';

  @override
  Widget build(BuildContext context) {

    TextEditingController _controller = new TextEditingController();

    return Scaffold(
      appBar: AppBar(title: Text('Bloc Example')),
      body: Center(
        child: Column(
          children: <Widget>[
          StreamBuilder(
            initialData: initialData,
            stream: bloc.nameStream,
              builder: (context, snapshot) {
                if ( snapshot.connectionState == ConnectionState.waiting)
                  _controller.text = snapshot.data;
                return TextField(
                  controller: _controller,
                  onChanged: bloc.nameChangedStream,
                  decoration: InputDecoration(labelText: 'Enter name' ),
                );
              }
            ),
            StreamBuilder(
              initialData: initialData,
              stream: bloc.nameStream, //
              builder: (context, snapshot) {
                return Text('Name is ${snapshot.hasData ? snapshot.data : 'unknown'}');
              }
            ),
          ],
        ),
      ),
    );
  }
}

class Bloc
{
  final nameStreamController = BehaviorSubject<String>();
  Stream<String> get nameStream => nameStreamController.stream;
  Function(String) get nameChangedStream => nameStreamController.sink.add ;
}

final Bloc bloc = new Bloc();

Я не могу понять, как указать начальное значение в поле моего имени.

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

ИЗМЕНИТЬ - благодаря предоставленным комментариям - обновил код, чтобы использовать комбинацию TextEditingController и StreamBuilder initialData и, похоже, работает нормально. С радостью приму дальнейшие комментарии, если есть лучшее решение :)


person cyteen02    schedule 18.04.2019    source источник
comment
можете ли вы предоставить решение, которое вы использовали?   -  person amarkovits    schedule 12.05.2019


Ответы (2)


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

final nameStreamController = BehaviorSubject<String>.seeded('InitialName');  

для более старых версий rxDart используйте

final nameStreamController = BehaviorSubject<String>(seedValue:'InitialName'); 
person nonybrighto    schedule 18.04.2019
comment
Спасибо за предложение. Если я добавлю начальное значение в свой пример кода, я увижу InitialName в моем текстовом виджете. Но я все еще пытаюсь заставить TextField иметь InitialName в качестве начального значения. Думаю, я мог бы использовать TextFormField и установить initialValue или использовать TextEditingController, но ни один из них не кажется особенно элегантным. - person cyteen02; 18.04.2019

Не зная, что вы хотите сделать с полем имени, вы можете пойти несколькими путями.

Вы можете поставить hintText на InputDecoration (InputDecoration(hintText: 'name')).

Вы можете установить начальное значение в StreamBuilder:

StreamBuilder(
  stream: bloc.nameStream,
  initialData: 'Initial Name',
    builder: (context, snapshot) {
      return TextField(
        onChanged: bloc.nameChangedStream,
        decoration: InputDecoration(labelText: 'Enter name' ),
      );
    }
  ),

Однако это значение не будет сохраняться в потоке, поэтому, если пользователь не изменит текстовое поле, «Начальное имя» не будет в потоке вашего nameStreamController.

Как упоминалось в @nonybrighto, вы можете заполнить свой nameStreamController начальным значением.

Если вы не можете использовать начальное значение, вы также можете добавить начальное значение в свой поток во время инициализации блока:

class Bloc {
  final nameStreamController = BehaviorSubject<String>();
  Stream<String> get nameStream => nameStreamController.stream;
  Function(String) get nameChangedStream => nameStreamController.sink.add;

  Bloc() {
    String initialValue = _getInitialValue();
    nameStreamController.add(initialValue);
  }
}

Вот более полный пример из реальной жизни: мы нашли этот пример аутентификации и входа в систему BLoC, в котором мы следовали многим материалам, изложенным здесь: Пример блока Дидье Боеленса. Он показывает вам, как можно использовать BLoC, реактивное программирование и потоки для настройки формы регистрации и авторизации.

person AKA    schedule 18.04.2019
comment
Мы совершенно забыли о раздаче вашего контроллера потока, так как подняли nonybrigh. Я бы пошел по этому пути вместо добавления значения во время инициализации, как показано в нашем последнем примере. - person AKA; 18.04.2019