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使って同じことしてみる。