admin管理员组文章数量:1279016
I have a widget 'A' that displays Text(currentPlayerStatus)
. This widget is called 10 times from another widget 'B', one for each player in the list to display each player's status. Initially, all the players have same status.
In widget 'B', there is a dropdown or a button or a GuestureDecetor that the user can interact with. When user selects one of the player, the corresponding widget, or taps the GuestureDetector, the 'A' for that player should update it's status from "not-set" to "set".
I tried passing globalKey
and key.currentState?.setStatus(status)
to call the setStatus
function in widget A, but the method is never invoked as the key.currentState?
always returns null
in this case.
How do I set state in a paticular Child widget of same type from a parent widget?
I hope I am clear with the question.
EDIT: Here is dartpad link: /6f016fe76a5ba392ac560cff43475bf3
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Center(child: B())),
);
}
}
Here is A
// Class A
class A extends StatefulWidget {
A({super.key, required this.status, required this.player});
String status;
Player player;
@override
State<A> createState() => _AState(status);
}
class _AState extends State<A> {
_AState(this.currentStatus);
String currentStatus;
void setStatus(String status) {
currentStatus = status;
}
@override
Widget build(BuildContext context) {
return Text(currentStatus);
}
}
Here is B and Player Class
// Player model
class Player {
String name;
String id;
Player({required this.name, required this.id});
}
//Class B
class B extends StatefulWidget {
@override
State<B> createState() => _BState();
}
class _BState extends State<B> {
List<Player> players = [];
List<String> statuses = [];
String placeholder = "This One";
@override
void initState() {
players = List.generate(
10,
(index) => Player(name: "Player $index", id: index.toString()),
);
statuses = List.generate(players.length, (index) => "not-set");
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children:
players.map((player) {
return Padding(
padding: EdgeInsets.all(8),
child: Row(
children: [
GestureDetector(
child: Text(player.name),
onTapDown: (onTap) {
// Set only this player status to 'set'
// The placeholder is only for attention.
setState(() {
placeholder = "only selected player's status should change";
});
},
),
SizedBox(width: 20),
A(player: player, status: statuses[players.indexOf(player)]),
SizedBox(width: 20),
Text(placeholder),
],
),
);
}).toList(),
);
}
}
I have a widget 'A' that displays Text(currentPlayerStatus)
. This widget is called 10 times from another widget 'B', one for each player in the list to display each player's status. Initially, all the players have same status.
In widget 'B', there is a dropdown or a button or a GuestureDecetor that the user can interact with. When user selects one of the player, the corresponding widget, or taps the GuestureDetector, the 'A' for that player should update it's status from "not-set" to "set".
I tried passing globalKey
and key.currentState?.setStatus(status)
to call the setStatus
function in widget A, but the method is never invoked as the key.currentState?
always returns null
in this case.
How do I set state in a paticular Child widget of same type from a parent widget?
I hope I am clear with the question.
EDIT: Here is dartpad link: https://dartpad.dev/6f016fe76a5ba392ac560cff43475bf3
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Center(child: B())),
);
}
}
Here is A
// Class A
class A extends StatefulWidget {
A({super.key, required this.status, required this.player});
String status;
Player player;
@override
State<A> createState() => _AState(status);
}
class _AState extends State<A> {
_AState(this.currentStatus);
String currentStatus;
void setStatus(String status) {
currentStatus = status;
}
@override
Widget build(BuildContext context) {
return Text(currentStatus);
}
}
Here is B and Player Class
// Player model
class Player {
String name;
String id;
Player({required this.name, required this.id});
}
//Class B
class B extends StatefulWidget {
@override
State<B> createState() => _BState();
}
class _BState extends State<B> {
List<Player> players = [];
List<String> statuses = [];
String placeholder = "This One";
@override
void initState() {
players = List.generate(
10,
(index) => Player(name: "Player $index", id: index.toString()),
);
statuses = List.generate(players.length, (index) => "not-set");
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children:
players.map((player) {
return Padding(
padding: EdgeInsets.all(8),
child: Row(
children: [
GestureDetector(
child: Text(player.name),
onTapDown: (onTap) {
// Set only this player status to 'set'
// The placeholder is only for attention.
setState(() {
placeholder = "only selected player's status should change";
});
},
),
SizedBox(width: 20),
A(player: player, status: statuses[players.indexOf(player)]),
SizedBox(width: 20),
Text(placeholder),
],
),
);
}).toList(),
);
}
}
Share
Improve this question
edited Feb 24 at 17:44
Anish Pokharel
asked Feb 24 at 3:43
Anish PokharelAnish Pokharel
215 bronze badges
3
|
4 Answers
Reset to default 1The widget 'A' should be StatelessWidget
that takes status
using a constructor. And then, widget 'B' should be StatefulWidget
which holds the status list, and calls setState
when user selects a player.
Here's an example:
class A extends StatelessWidget {
const A({
super.key,
required this.status,
});
final String status;
@override
Widget build(BuildContext context) {
return Text(status);
}
}
class B extends StatefulWidget {
const B({super.key});
@override
State<B> createState() => _BState();
}
class _BState extends State<B> {
final List<String> statuses = [
'unselected',
'unselected',
'unselected',
'unselected',
];
void _onSelected(int index) {
setState(() {
statuses[index] = 'selected';
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: statuses.length,
itemBuilder: (context, index) {
return A(status: statuses[index]);
},
);
}
}
I am not exactly sure of your requirements. Here, is my attempt to solving your problem. Hope it helps.
Full code:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(home: const B());
}
}
class B extends StatefulWidget {
const B({super.key});
@override
State<B> createState() => _BState();
}
class _BState extends State<B> {
Map<String, String> playerSelectedStatus = {
"Player01": "notSelected",
"Player02": "notSelected",
"Player03": "notSelected",
"Player04": "notSelected",
"Player05": "notSelected",
};
late String? myDropdownValue = playerSelectedStatus.keys.first;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Example"),
backgroundColor: Colors.blue,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Column(
children: [
DropdownMenu<String>(
initialSelection: myDropdownValue,
onSelected: (String? value) {
setState(() {
playerSelectedStatus[value!] = "selected";
});
},
dropdownMenuEntries:
playerSelectedStatus.keys
.toList()
.map<DropdownMenuEntry<String>>((String tmpStr) {
return DropdownMenuEntry(value: tmpStr, label: tmpStr);
})
.toList(),
),
A(myMap: playerSelectedStatus),
],
),
),
);
}
}
class A extends StatelessWidget {
final Map<String, String> myMap;
const A({super.key, required this.myMap});
@override
Widget build(BuildContext context) {
final entries = myMap.entries.toList();
return Container(
height: 150,
decoration: BoxDecoration(color: Colors.blue.shade100),
child: Column(
children: [
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: entries.length,
itemBuilder: (context, index) {
final entry = entries[index];
return Text("${entry.key} is ${entry.value}");
},
),
),
],
),
);
}
}
globalKey.currentState?.setStatus()
was coming out null and I was unable to use it to update the child because I was doing it wrong. The key that I initially used returned currentState
to be null because I was passing it a wrong way. Here is how I fixed it and got the desired outcome.
https://dartpad.dev/26b9afdbddac1cd18992412bacf77a6e
I was also trying to solve your problem, and I've come up with the following using provider
package to do the state management. Please see if it helps.
lib/main.dart:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:set_state_of_a_child_widget_from_parent/class_B.dart';
import 'package:set_state_of_a_child_widget_from_parent/my_custom_provider.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<MyCustomProvider>(
create: (context) => MyCustomProvider(),
),
],
child: const MyApp(),
),
);
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Center(child: B())),
);
}
}
lib/class_player.dart:
// Player model
class Player {
String name;
String id;
Player({required this.name, required this.id});
}
lib/class_B.dart:
//Class B
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:set_state_of_a_child_widget_from_parent/class_A.dart';
import 'package:set_state_of_a_child_widget_from_parent/class_player.dart';
import 'package:set_state_of_a_child_widget_from_parent/my_custom_provider.dart';
class B extends StatefulWidget {
@override
State<B> createState() => _BState();
}
class _BState extends State<B> {
List<Player> players = [];
List<String> statuses = [];
String placeholder = "This One";
MyCustomProvider? myCustomProviderObj;
@override
void initState() {
super.initState();
players = List.generate(
10,
(index) => Player(name: "Player $index", id: index.toString()),
);
statuses = List.generate(players.length, (index) => "not-set");
myCustomProviderObj = Provider.of<MyCustomProvider>(context, listen: false);
}
@override
Widget build(BuildContext context) {
return Column(
children:
players.map((player) {
return Padding(
padding: EdgeInsets.all(8),
child: Row(
children: [
GestureDetector(
child: Text(player.name),
onTapDown: (onTap) {
myCustomProviderObj!.updatePlayerStatus(player);
},
),
SizedBox(width: 20),
Consumer<MyCustomProvider>(
builder: (context, myProvider, child) {
if (myProvider.updatedPlayers.contains(player)) {
return A(player: player, status: "selected");
} else {
return A(player: player, status: "not-set");
}
},
),
SizedBox(width: 20),
Text(placeholder),
],
),
);
}).toList(),
);
}
}
lib/class_A.dart:
// Class A
import 'package:flutter/material.dart';
import 'package:set_state_of_a_child_widget_from_parent/class_player.dart';
class A extends StatefulWidget {
const A({super.key, required this.status, required this.player});
final String status;
final Player player;
@override
State<A> createState() => _AState();
}
class _AState extends State<A> {
@override
Widget build(BuildContext context) {
return Text(widget.status);
}
}
lib/my_custom_provider.dart:
import 'package:flutter/widgets.dart';
import 'package:set_state_of_a_child_widget_from_parent/class_player.dart';
class MyCustomProvider with ChangeNotifier {
List<Player> updatedPlayers = [];
void updatePlayerStatus(Player player) {
updatedPlayers.add(player);
notifyListeners();
}
}
本文标签: flutterHow to set state of a child widget from the parent widgetStack Overflow
版权声明:本文标题:flutter - How to set state of a child widget from the parent widget? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741295216a2370779.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
A(player: player, status: statuses[players.indexOf(player)]),
resets every changes you make in theonTap
andsetState
as setState will cause the build method to build again. You may need to search a different approach. – rusty Commented Feb 27 at 6:03provider
package for state management. Please check out the answer. – rusty Commented Feb 28 at 2:26