使用 Provider.of 后如何保持实例化变量不变
How do I keep a instantiated variable unchanged after using Provider.of
我有一个页面,我可以在其中选择用作我的应用程序颜色的用户主题颜色。我已经设置好了,所以模态底部 sheet 会弹出颜色选项,然后使用 Provider 设置它,这样当弹出导航时,可以在 MyView 上看到新颜色。
问题
当用户进行更改但点击关闭按钮时,我基本上想恢复所做的所有更改,因此为了尝试解决这个问题,我有一个名为 loggedInUser 的变量,我在我的 init State 函数中初始化它并且我不在构建方法。所以它设置一次,就是这样。计划是,如果用户点击关闭按钮,我使用 Provider 将详细信息设置回 loggedInUser 中的数据(不应该有更新的颜色选择)。
这不会发生,loggedInUser 虽然没有重新初始化但具有我选择的新颜色。
代码
class MyView extends StatefulWidget {
static const String id = "my_view";
@override
State<MyView> createState() => _MyViewState();
}
class _MyViewState extends State<MyView> {
UserDto loggedInUser;
@override
void initState() {
super.initState();
loggedInUser = Provider.of<UserData>(context, listen: false).user;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: kThemeColor,
body: Column(
children: [
SafeArea(
child: CloseButton(
onPressed: () {
var test = loggedInUser;
//when debugged, test has the new color, not the old one it was initialised to back in initState();
//i want the old values to persist
Navigator.pop(context);
},
color: Colors.white,
),
),
Expanded(
child: Container(
height: double.infinity,
width: double.infinity,
decoration: kCurvedContainerBoxDecoration,
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
bottom:
MediaQuery.of(context).viewInsets.bottom),
child: AccountThemePickerView(),
),
),
);
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
UserHelper.getColorFromString(
Provider.of<UserData>(context).user.themeColor),
),
shape:
MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
),
)
],
),
),
),
)
],
),
);
}
}
class AccountThemePickerView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Color(0xff757575),
child: Container(
decoration: kModalBottomSheetBoxDecoration,
padding: EdgeInsets.only(left: 15, bottom: 30, right: 15, top: 15),
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 3,
crossAxisSpacing: 30,
mainAxisSpacing: 30,
children: [
AccountThemePickerColor(
colorName: "Coral Red", color: Color(0xffff6961)),
AccountThemePickerColor(
colorName: "Forest Green", color: Color(0xff129a7d)),
],
),
),
);
}
}
class AccountThemePickerColor extends StatelessWidget {
final Color color;
final String colorName;
AccountThemePickerColor({this.colorName, this.color});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
Provider.of<UserData>(context, listen: false)
.updateUserThemeColor(colorName, color.toString());
Navigator.pop(context);
},
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
backgroundColor: MaterialStateProperty.all<Color>(color),
),
);
}
}
用户数据class
class UserData extends ChangeNotifier{
UserDto user;
void setUser(UserDto userDto){
user = userDto;
notifyListeners();
}
void updateUserThemeColor(String themeColorName, String themeColor){
//note I have a helper method which simply converts string to color, for your debug purposes you can just use an actual Color value
user.themeColor = themeColor;
user.themeColorName = themeColorName;
notifyListeners();
}
}
我相信它与复制构造函数有关。
例如,这段代码:
class X{
int y;
int z;
X(this.y, this.z);
}
void main() {
X obj1 = X(2,3);
X obj2 = obj1;
X obj3 = obj2;
obj1.y = 10;
print(obj2.y);
print(obj3.y);
}
产出
10
10
因为变量是对对象的引用。并且当您将一个对象分配给另一个对象时,它指向内存中的相同位置,而不是复制其元素。
Provider.of<UserData>(context, listen: false).user;
每次调用时都会 return 同一个对象。所以,你改变了它的价值。因此,loggedInUser 也会发生变化。
尝试create
一个新对象并在其中存储数据。
我有一个页面,我可以在其中选择用作我的应用程序颜色的用户主题颜色。我已经设置好了,所以模态底部 sheet 会弹出颜色选项,然后使用 Provider 设置它,这样当弹出导航时,可以在 MyView 上看到新颜色。
问题
当用户进行更改但点击关闭按钮时,我基本上想恢复所做的所有更改,因此为了尝试解决这个问题,我有一个名为 loggedInUser 的变量,我在我的 init State 函数中初始化它并且我不在构建方法。所以它设置一次,就是这样。计划是,如果用户点击关闭按钮,我使用 Provider 将详细信息设置回 loggedInUser 中的数据(不应该有更新的颜色选择)。
这不会发生,loggedInUser 虽然没有重新初始化但具有我选择的新颜色。
代码
class MyView extends StatefulWidget {
static const String id = "my_view";
@override
State<MyView> createState() => _MyViewState();
}
class _MyViewState extends State<MyView> {
UserDto loggedInUser;
@override
void initState() {
super.initState();
loggedInUser = Provider.of<UserData>(context, listen: false).user;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: kThemeColor,
body: Column(
children: [
SafeArea(
child: CloseButton(
onPressed: () {
var test = loggedInUser;
//when debugged, test has the new color, not the old one it was initialised to back in initState();
//i want the old values to persist
Navigator.pop(context);
},
color: Colors.white,
),
),
Expanded(
child: Container(
height: double.infinity,
width: double.infinity,
decoration: kCurvedContainerBoxDecoration,
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
bottom:
MediaQuery.of(context).viewInsets.bottom),
child: AccountThemePickerView(),
),
),
);
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
UserHelper.getColorFromString(
Provider.of<UserData>(context).user.themeColor),
),
shape:
MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
),
)
],
),
),
),
)
],
),
);
}
}
class AccountThemePickerView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Color(0xff757575),
child: Container(
decoration: kModalBottomSheetBoxDecoration,
padding: EdgeInsets.only(left: 15, bottom: 30, right: 15, top: 15),
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 3,
crossAxisSpacing: 30,
mainAxisSpacing: 30,
children: [
AccountThemePickerColor(
colorName: "Coral Red", color: Color(0xffff6961)),
AccountThemePickerColor(
colorName: "Forest Green", color: Color(0xff129a7d)),
],
),
),
);
}
}
class AccountThemePickerColor extends StatelessWidget {
final Color color;
final String colorName;
AccountThemePickerColor({this.colorName, this.color});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
Provider.of<UserData>(context, listen: false)
.updateUserThemeColor(colorName, color.toString());
Navigator.pop(context);
},
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
backgroundColor: MaterialStateProperty.all<Color>(color),
),
);
}
}
用户数据class
class UserData extends ChangeNotifier{
UserDto user;
void setUser(UserDto userDto){
user = userDto;
notifyListeners();
}
void updateUserThemeColor(String themeColorName, String themeColor){
//note I have a helper method which simply converts string to color, for your debug purposes you can just use an actual Color value
user.themeColor = themeColor;
user.themeColorName = themeColorName;
notifyListeners();
}
}
我相信它与复制构造函数有关。
例如,这段代码:
class X{
int y;
int z;
X(this.y, this.z);
}
void main() {
X obj1 = X(2,3);
X obj2 = obj1;
X obj3 = obj2;
obj1.y = 10;
print(obj2.y);
print(obj3.y);
}
产出
10
10
因为变量是对对象的引用。并且当您将一个对象分配给另一个对象时,它指向内存中的相同位置,而不是复制其元素。
Provider.of<UserData>(context, listen: false).user;
每次调用时都会 return 同一个对象。所以,你改变了它的价值。因此,loggedInUser 也会发生变化。
尝试create
一个新对象并在其中存储数据。