问题
i try to edit the value of the child widget, i can do it with StatefulWidget parent but i want to do it with StatelessWidget parent and without using global value
class Homepage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(child: Text('addFile'), onPressed: () {}),
FlatButton(child: Text('deleteFile'), onPressed: () {})
],
),
body: Child(),
);
}
}
class Child extends StatefulWidget {
@override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
var hasFile = true;
@override
Widget build(BuildContext context) {
return hasFile ? Text('has a file') : Text("no File");
}
}
回答1:
You are thinking the wrong way. Child aka Text() should get its value from a model which is managed by the application or at least managed by the widget above. I would go with the provider package https://pub.dev/packages/provider and do this:
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
class MyState with ChangeNotifier {
String _myText;
MyState(this._myText);
getMyText() => _myText;
void changeText(String newText) {
_myText = newText;
notifyListeners();
}
}
class Homepage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => MyState("initial Text")),
],
child: Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(
child: Text('addFile'),
onPressed: () {
Provider.of<MyState>(context).changeText("addFile");
}),
FlatButton(
child: Text('deleteFile'),
onPressed: () {
Provider.of<MyState>(context).changeText("deleteFile");
})
],
),
body: Child(),
));
}
}
class Child extends StatelessWidget {
@override
Widget build(BuildContext context) {
MyState myState = Provider.of<MyState>(context);
return Text(myState.getMyText());
}
}
This is coded without IDE support or even compiling and running. But it should get you to the right direction.
回答2:
You can use BLoC pattern to implement this kind of functionality,
Here is the BLoC class which will handle state of bool
import 'dart:async';
class Bloc {
final _fileController = StreamController<bool>();
changeState(bool val) {
_fileController.sink.add(val);
}
get hasFile => _fileController.stream;
dispose() {
_fileController.close();
}
}
final bloc = Bloc();
Then you can add stream builder in your Stateful Widget, in which you will provide stream of BLoC class. StreamBuilder updates it's UI according to Stream.
class Child extends StatefulWidget {
@override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
var hasFile = true;
@override
void dispose() {
bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: bloc.hasFile,
initialData: false,
builder: (context, snapshot) {
return snapshot.data ? Text('has a file') : Text("no File");
},
);
}
}
At last you can access BLoC class with your stateless widget as follows
class Homepage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(
child: Text('addFile'),
onPressed: () {
bloc.changeState(true);
}),
FlatButton(
child: Text('deleteFile'),
onPressed: () {
bloc.changeState(false);
})
],
),
body: Child(),
);
}
}
Full example is as below
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Homepage(),
);
}
}
class Homepage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
FlatButton(
child: Text('addFile'),
onPressed: () {
bloc.changeState(true);
}),
FlatButton(
child: Text('deleteFile'),
onPressed: () {
bloc.changeState(false);
})
],
),
body: Child(),
);
}
}
class Child extends StatefulWidget {
@override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
var hasFile = true;
@override
void dispose() {
bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: bloc.hasFile,
initialData: false,
builder: (context, snapshot) {
return snapshot.data ? Text('has a file') : Text("no File");
},
);
}
}
class Bloc {
final _fileController = StreamController<bool>();
changeState(bool val) {
_fileController.sink.add(val);
}
get hasFile => _fileController.stream;
dispose() {
_fileController.close();
}
}
final bloc = Bloc();
来源:https://stackoverflow.com/questions/57969370/how-to-edit-value-at-the-child-widget