用于局部和全局变量的 Flutter Riverpod
Flutter Riverpod for local and global variables
我有两个文本编辑控制器,我正在尝试为这些文本编辑控制器提供从 api 获取的初始值。我需要全局声明文本编辑控制器并从 api 中给出初始值,所以我需要的是对全局变量使用 data3.firstName 和 data3.lastName,如果我尝试声明构建它的变量和函数不起作用,所以只需要将获取的数据用于全局文本编辑控制器,这样我就可以给出初始值。
late Future<Response> futureData;
@override
void initState() {
super.initState();
futureData = fetchAccountData();
}
final _formKey = GlobalKey<FormState>();
TextEditingController editedFirstName =
TextEditingController(text: 'Hello'); // needs to be data3.firsName
TextEditingController editedLastName = TextEditingController(text: 'Riverpod looks great');// needs to be data3.lastName
Future<void> putAccountData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? authorization = prefs.getString('authorization');
var url = 'https://dev.api.wurk.skyver.co/api/v1/employees/account';
Map payload = {
"firstName": editedFirstName.text,
"lastName": editedLastName.text,
};
try {
final response = await http.put(Uri.parse(url),
headers: <String, String>{
'authorization': authorization ?? basicAuth.toString(),
"Content-Type": "application/json"
},
body: jsonEncode(payload));
} catch (er) {}
}
@override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return SafeArea(
child: WillPopScope(
onWillPop: () async {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
);
return shouldPop;
},
child: KeyboardDismisser(
gestures: const [
GestureType.onTap,
GestureType.onPanUpdateDownDirection
],
child: Form(
key: _formKey,
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: Colors.blue,
title: const Text(
'Edit My Profile',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
);
},
),
),
body: FutureBuilder<Response>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.hasData) {
AccountData data3 = AccountData.fromJson(
json.decode(snapshot.data!.body),
);
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: width,
height: height / 1.9,
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 3,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
children: [
const Padding(
padding: EdgeInsets.all(30),
child: Text(
"First Name:",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(30),
child: SizedBox(
width: width / 2.5,
child: Center(
child: TextFormField(
textAlignVertical:
TextAlignVertical.center,
//initialValue: editedFirstName.text = data3.firstName,
controller: editedFirstName,
// ..selection =
// TextSelection.collapsed(
// offset: data3
// .firstName.length),
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
borderSide: const BorderSide(
color: Colors.red,
width: 1),
),
),
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
),
// inputFormatters: [
// LengthLimitingTextInputFormatter(15)
// ],
validator: (value) {
if (value == null ||
value.isEmpty) {
return 'Name is required';
}
return null;
},
),
),
),
),
],
),
Row(
children: [
const Padding(
padding: EdgeInsets.all(30),
child: Text(
'Last Name:',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(30),
child: SizedBox(
width: width / 2.5,
child: TextFormField(
//initialValue: editedLastName.text = data3.lastName,
controller: editedLastName,
// ..selection =
// TextSelection.collapsed(
// offset:
// data3.lastName.length),
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
),
),
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold),
),
),
),
],
),
您似乎想为 TextField
提供初始值,但该值是从服务器异步获取的。
您使用 TextEditingController
的方向是正确的,但是由于您一开始没有准备好值,因此在创建控制器时不应使用 TextEditingController(text: 'Hello')
。
相反,您可以创建一个没有默认值的控制器,例如:final _controller = TextEditingController()
。然后在你得到数据之后,比如在 initState
中调用 fetchAccountData()
方法后,你可以使用 _controller.text = fetchedValue
.
将数据分配给控制器
我看到你也在使用 FutureBuilder
。根据加载“默认值”之前要显示的内容,您可能需要也可能不需要 FutureBuilder
。
快速演示:
class QuickDemo extends StatefulWidget {
const QuickDemo({Key? key}) : super(key: key);
@override
_QuickDemoState createState() => _QuickDemoState();
}
class _QuickDemoState extends State<QuickDemo> {
final _controller = TextEditingController();
@override
void initState() {
super.initState();
_fetchData();
}
_fetchData() async {
// do your network call here
await Future.delayed(const Duration(seconds: 1));
// and then parse your response here
final data = 'Hello';
// eventually you will have data, so assign it:
_controller.text = data;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextField(
controller: _controller,
),
),
);
}
}
我有两个文本编辑控制器,我正在尝试为这些文本编辑控制器提供从 api 获取的初始值。我需要全局声明文本编辑控制器并从 api 中给出初始值,所以我需要的是对全局变量使用 data3.firstName 和 data3.lastName,如果我尝试声明构建它的变量和函数不起作用,所以只需要将获取的数据用于全局文本编辑控制器,这样我就可以给出初始值。
late Future<Response> futureData;
@override
void initState() {
super.initState();
futureData = fetchAccountData();
}
final _formKey = GlobalKey<FormState>();
TextEditingController editedFirstName =
TextEditingController(text: 'Hello'); // needs to be data3.firsName
TextEditingController editedLastName = TextEditingController(text: 'Riverpod looks great');// needs to be data3.lastName
Future<void> putAccountData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? authorization = prefs.getString('authorization');
var url = 'https://dev.api.wurk.skyver.co/api/v1/employees/account';
Map payload = {
"firstName": editedFirstName.text,
"lastName": editedLastName.text,
};
try {
final response = await http.put(Uri.parse(url),
headers: <String, String>{
'authorization': authorization ?? basicAuth.toString(),
"Content-Type": "application/json"
},
body: jsonEncode(payload));
} catch (er) {}
}
@override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return SafeArea(
child: WillPopScope(
onWillPop: () async {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
);
return shouldPop;
},
child: KeyboardDismisser(
gestures: const [
GestureType.onTap,
GestureType.onPanUpdateDownDirection
],
child: Form(
key: _formKey,
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: Colors.blue,
title: const Text(
'Edit My Profile',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
);
},
),
),
body: FutureBuilder<Response>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.hasData) {
AccountData data3 = AccountData.fromJson(
json.decode(snapshot.data!.body),
);
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: width,
height: height / 1.9,
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 3,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
children: [
const Padding(
padding: EdgeInsets.all(30),
child: Text(
"First Name:",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(30),
child: SizedBox(
width: width / 2.5,
child: Center(
child: TextFormField(
textAlignVertical:
TextAlignVertical.center,
//initialValue: editedFirstName.text = data3.firstName,
controller: editedFirstName,
// ..selection =
// TextSelection.collapsed(
// offset: data3
// .firstName.length),
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
borderSide: const BorderSide(
color: Colors.red,
width: 1),
),
),
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
),
// inputFormatters: [
// LengthLimitingTextInputFormatter(15)
// ],
validator: (value) {
if (value == null ||
value.isEmpty) {
return 'Name is required';
}
return null;
},
),
),
),
),
],
),
Row(
children: [
const Padding(
padding: EdgeInsets.all(30),
child: Text(
'Last Name:',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(30),
child: SizedBox(
width: width / 2.5,
child: TextFormField(
//initialValue: editedLastName.text = data3.lastName,
controller: editedLastName,
// ..selection =
// TextSelection.collapsed(
// offset:
// data3.lastName.length),
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
),
),
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold),
),
),
),
],
),
您似乎想为 TextField
提供初始值,但该值是从服务器异步获取的。
您使用 TextEditingController
的方向是正确的,但是由于您一开始没有准备好值,因此在创建控制器时不应使用 TextEditingController(text: 'Hello')
。
相反,您可以创建一个没有默认值的控制器,例如:final _controller = TextEditingController()
。然后在你得到数据之后,比如在 initState
中调用 fetchAccountData()
方法后,你可以使用 _controller.text = fetchedValue
.
我看到你也在使用 FutureBuilder
。根据加载“默认值”之前要显示的内容,您可能需要也可能不需要 FutureBuilder
。
快速演示:
class QuickDemo extends StatefulWidget {
const QuickDemo({Key? key}) : super(key: key);
@override
_QuickDemoState createState() => _QuickDemoState();
}
class _QuickDemoState extends State<QuickDemo> {
final _controller = TextEditingController();
@override
void initState() {
super.initState();
_fetchData();
}
_fetchData() async {
// do your network call here
await Future.delayed(const Duration(seconds: 1));
// and then parse your response here
final data = 'Hello';
// eventually you will have data, so assign it:
_controller.text = data;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextField(
controller: _controller,
),
),
);
}
}