Не обновляется текст при нажатии на кнопку
Имеется 2 виджета: MyHomePage и Buttons. Где в MyHomePage должна отображаться информация из List'а, а Buttons просто как отдельный "кастомный виджет". Во время того, как я нажимаю на кнопку у меня должен менятся id для того, чтобы определить какой итем из List'a нужно отобразить в MyHomePage.
class _ButtonsState extends State<Buttons> {
var s = Logic();
void _func(int id) {
setState(() {
s.id = id;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
MaterialButton(
onPressed: () => _func(1),
child: Text('Text 1'),
),
MaterialButton(
onPressed: () => _func(2),
child: Text('Text 2'),
),
],
);
}
}
Но при нажатии на кнопку информация не обновляется, хотя в MyHomePage есть StreamBuilder
class _MyHomePageState extends State<MyHomePage> {
var s = Logic();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder<String>(
stream: s.stream(),
builder: (context, snapshot) {
if (snapshot.data != null && snapshot.hasData) {
return Text(
'${snapshot.data}',
style: Theme.of(context).textTheme.headline4,
);
} else {
return Container(
width: 100,
height: 100,
color: Colors.red,
);
}
},
),
Buttons(),
],
),
),
);
}
}
Вот код самого Stream на который я подписывался в StreamBuilder
class Logic {
int? id;
var text = ListStrings();
Stream<String>? stream() {
if (id == 1) {
return Stream.value(text.text[0]);
} else if (id == 2) {
return Stream.value(text.text[1]);
} else {
return null;
}
}
}
сам id в классе Logic обновляется при нажатии на кнопку. В чем заключается ошибка?
Ответы (1 шт):
Автор решения: ddo5
→ Ссылка
- В вашем примере
Logic.streamвозвращает стрим с единственным значением, которое никак не может обновиться. То есть это эквивалентно следующему:
class Logic {
int? id;
var text = ListStrings();
String? getText() {
if (id == 1) {
return text.text[0];
} else if (id == 2) {
return text.text[1];
} else {
return null;
}
}
}
class _MyHomePageState extends State<MyHomePage> {
var s = Logic();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
${s.getText()}',
style: Theme.of(context).textTheme.headline4,
),
Buttons(),
],
),
),
);
}
}
- Сам факт того, что
var sв_ButtonsStateиvar sв_MyHomePageState- это два разных объекта, уже не позволит реализовать правильную логику.
Могу предложить следующий способ решения проблемы:
class MyHomePage extends StatefulWidget {
MyHomePage({required this.title});
final String title;
@override
State<StatefulWidget> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Объявляем s только в одном месте
final s = Logic();
@override
void dispose() {
// Закрываем контроллер
s.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder<String?>(
stream: s.textStream,
builder: (context, snapshot) {
if (snapshot.data != null && snapshot.hasData) {
return Text(
'${snapshot.data}',
style: Theme.of(context).textTheme.headline4,
);
} else {
return Container(
width: 100,
height: 100,
color: Colors.red,
);
}
},
),
Buttons(s: s),
],
),
),
);
}
}
class Buttons extends StatefulWidget {
Buttons({required this.s});
final Logic s;
@override
State<StatefulWidget> createState() => _ButtonsState();
}
class _ButtonsState extends State<Buttons> {
void _func(int id) {
// Теперь при задании id, новое значение будет приходить в _idController
widget.s.id = id;
}
@override
Widget build(BuildContext context) {
return Column(
children: [
MaterialButton(
onPressed: () => _func(1),
child: Text('Text 1'),
),
MaterialButton(
onPressed: () => _func(2),
child: Text('Text 2'),
),
],
);
}
}
class Logic {
final text = ListStrings();
int? _id;
int? get id => _id;
set id(int? newValue) {
_id = newValue;
_idController.add(newValue);
}
final _idController = StreamController<int?>();
Stream<String?> get textStream {
// Трансформируем стрим для того, чтобы получать не id, а значение из списка text.text
return _idController.stream.map<String?>(
(id) {
if (id == null) return null;
final textIndex = id - 1;
// Если индекс не входит в границы списка, возвращаем null
if (textIndex < 0 || textIndex >= text.text.length) return null;
return text.text[textIndex];
},
);
}
void dispose() {
_idController.close();
}
}