flutter StreamBuilderから遷移した画面のStreamBuilder内のTextFieldを初期化する
困った。StreamBuilderで作ったList画面から、これまたStremBuilderで作ったEdit画面へ画面遷移。
Edit画面のStreamBuilder内にTextFieldを置いて、Streamから取得した値で初期化しようとすると、キーボードを表示する度にStreamが流れてしまい、編集しようとも初期化しようとする値に戻ってしまう。
EditScreenのStremが流れるたびに呼び出し元のListScreenにもStreamが流れてしまい、想定した動きにならない。
仕方ないのでEditScreenに初期化済み判定用のフラグを用意してみた。
class ListScreen extends StatelessWidget { // APIからデータを取得してストリームに流し込むことを想定 Stream<List<String>> _stream = Stream<List<String>>.value( ["Title1", "Title2", "Title3", "Title4", "Title5"]); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("First Screen")), body: StreamBuilder( stream: _stream, builder: (context, AsyncSnapshot<List<String>> snapshot) { if (!snapshot.hasData) { return Container(); } return ListView.builder( itemCount: snapshot.data.length, itemBuilder: (context, index) { return InkWell( onTap: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => DetailScreen(), )); }, child: Card( child: Container( margin: EdgeInsets.all(10.0), child: Text(snapshot.data[index])), ), ); }); }, )); } } class DetailScreen extends StatefulWidget { DetailScreen(); @override State<StatefulWidget> createState() => DetailScreenState(); } class DetailScreenState extends State<DetailScreen> { // APIから取得してデータをストリームに流し込むことを想定 Stream<String> _stream = Stream<String>.value("this is id='s data"); // TextFieldを初期化済みかどうかを管理するためのフラグ bool _initialize = false; final _titleTextController = TextEditingController(); Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Second Screen")), body: StreamBuilder( stream: _stream, builder: (context, AsyncSnapshot<String> snapshot) { if (!snapshot.hasData) { return Container(); } else if (!_initialize) { // ストリームから流れてきたデータをTextFieldの初期値にセット // ただしSoftwareKeyboardの表示・非表示が切り替わるたびにStreamが // 流れてくるため、初期化済みか判定用のフラグ管理する _titleTextController.text = snapshot.data; _initialize = true; } return Container( child: Column( children: <Widget>[ TextFormField( controller: _titleTextController, decoration: InputDecoration(labelText: "Title"), ), ], ), ); }), ); } }
これはもうちょっと使い方調べないとダメやな。
provider packageのStreamProvider使って同じことしてみる。