开关/复选框未在 setState() 上更新
Posted
技术标签:
【中文标题】开关/复选框未在 setState() 上更新【英文标题】:Switch/Checkbox not updating on setState() 【发布时间】:2021-10-31 07:40:51 【问题描述】:我已经这样做了 4 天,阅读了一半的 Google 内容并观看了 3/4 的 Youtube。我有一个对象列表,我正在从 API 获取数据。当这些对象生成卡片时,Checkbox 的 Switch 不起作用,setState 根本不会影响它们。这是原始代码,在我开始尝试并弄乱代码之前(感谢 Git)。
有人有什么想法吗?
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mojmegatel/API/get_settings_api.dart';
import 'package:mojmegatel/api/set_settings_api.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import '../constants.dart';
import 'dart:io';
class SettingsArray extends StatefulWidget
final ValueChanged onChanged;
final bool isSwitched;
const SettingsArray(
required this.onChanged,
required this.isSwitched,
Key? key,
) : super(key: key);
@override
_SwitchWidget createState() => _SwitchWidget();
class _SwitchWidget extends State<SettingsArray>
Future? dataFuture;
bool isSwitched = false;
@override
void initState()
isSwitched = false;
dataFuture = _getData();
super.initState();
_getData() async
await GetSettings();
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
String sharedPrefsSettings = sharedPrefs.getString('settings').toString();
String jsonSettings = await DefaultAssetBundle.of(context).loadString("assets/json/settings_data.json");
String mergedData = await MergeData(jsonSettings, sharedPrefsSettings);
return mergedData;
Future<String> MergeData(String jsonSettings, String sharedPrefsSettings) async
var decodedJsonSettings = json.decode(jsonSettings);
var decodedSharedPrefsSettings = json.decode(sharedPrefsSettings);
String mergedSettings = '[';
bool found_id = false;
bool is_last = false;
String service_id;
String name;
String description;
String servicerequestvalue;
for (int i = 0; i < decodedJsonSettings.length; i++)
for (int j = 0; j < decodedSharedPrefsSettings.length; j++)
if (decodedJsonSettings[i]['service_id'] == decodedSharedPrefsSettings[j]['service_id'])
found_id = true;
service_id = decodedJsonSettings[i]['service_id'];
name = decodedJsonSettings[i]['title'];
description = decodedJsonSettings[i]['description'];
servicerequestvalue = decodedSharedPrefsSettings[j]['servicerequestvalue'];
mergedSettings += '"service_id": "$service_id",';
mergedSettings += '"name": "$name",';
mergedSettings += '"description": "$description",';
mergedSettings += '"servicerequestvalue": "$servicerequestvalue"';
if (i == decodedJsonSettings.length - 1 && j == decodedSharedPrefsSettings.length - 1)
// Nothing, don't complicate
else
mergedSettings += ',';
if (found_id == false)
service_id = decodedJsonSettings[i]['service_id'];
name = decodedJsonSettings[i]['title'];
description = decodedJsonSettings[i]['description'];
mergedSettings += '"service_id": "$service_id",';
mergedSettings += '"name": "$name",';
mergedSettings += '"description": "$description",';
mergedSettings += '"servicerequestvalue": "0"';
if (i == decodedJsonSettings.length - 1)
// Nothing, don't complicate
else
mergedSettings += ',';
else
found_id = false;
mergedSettings += ']';
return mergedSettings;
Widget build(BuildContext context)
List<Widget> widgetList = <Widget>[];
return ListView.builder(
shrinkWrap: true,
physics: ScrollPhysics(),
itemCount: 1,
itemBuilder: (context, index)
return FutureBuilder(
future: dataFuture,
builder: (context, snapshot)
if (snapshot.data != null)
String service_id;
String name;
String description;
var settingsData = json.decode(snapshot.data.toString());
List<dynamic> list = settingsData;
widgetList = <Widget>[];
for (int i = 0; i < list.length; i++)
String serviceRequestValue = settingsData[i]['servicerequestvalue'].toString();
bool serviceRequestValueBool = true;
service_id = settingsData[i]['service_id'].toString();
name = settingsData[i]['name'].toString();
description = settingsData[i]['description'].toString();
log(service_id);
if (serviceRequestValue == "1" || serviceRequestValue == "1,1" || serviceRequestValue == "14")
serviceRequestValueBool = true;
else
serviceRequestValueBool = false;
widgetList.add(settingsContainer(service_id, service_id, name, description, serviceRequestValueBool));
return Column(children: widgetList.toList());
return Column(
children: [
Container(
width: 60.0,
height: 80.0,
padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: SpinKitFoldingCube(color: MojMegaTelTheme.megaTelBlue), // CircularProgressIndicator(),
),
],
);
,
);
,
);
Widget settingsContainer(String key, String serviceId, String title, String description, bool isSwitched)
return Padding(
key: ValueKey(key),
padding: const EdgeInsets.only(left: 24, right: 24, top: 16, bottom: 18),
child: Container(
decoration: BoxDecoration(
color: MojMegaTelTheme.white,
borderRadius: BorderRadius.only(topLeft: Radius.circular(8.0), bottomLeft: Radius.circular(8.0), bottomRight: Radius.circular(8.0), topRight: Radius.circular(8.0)),
boxShadow: <BoxShadow>[
BoxShadow(color: MojMegaTelTheme.grey.withOpacity(0.2), offset: Offset(1.1, 1.1), blurRadius: 10.0),
],
),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 16, left: 16, right: 24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 4, bottom: 3),
child: Row(
children: [
Text(
title,
overflow: TextOverflow.fade,
maxLines: 1,
softWrap: false,
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: MojMegaTelTheme.fontName,
fontWeight: FontWeight.w600,
fontSize: 14,
color: MojMegaTelTheme.darkerText,
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 8),
child: Row(
children: [
Checkbox(
value: isSwitched,
onChanged: (value)
setState(
()
isSwitched = value!;
log("Swich: " + isSwitched.toString());
,
);
,
),
],
),
),
],
),
],
)
],
),
),
Padding(
padding: const EdgeInsets.only(left: 24, right: 24, top: 8, bottom: 8),
child: Container(
height: 2,
decoration: BoxDecoration(
color: MojMegaTelTheme.background,
borderRadius: BorderRadius.all(Radius.circular(4.0)),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 24, right: 24, top: 8, bottom: 16),
child: Row(
children: <Widget>[
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 6),
child: Text(
description,
textAlign: TextAlign.left,
style: TextStyle(
fontFamily: MojMegaTelTheme.fontName,
fontWeight: FontWeight.w600,
fontSize: 12,
color: MojMegaTelTheme.grey.withOpacity(0.5),
),
),
),
],
),
),
],
),
)
],
),
),
);
【问题讨论】:
我认为问题出在 isSwitched 上。为什么你在两个班级都设置它?似乎每次重建此小部件时,它都会将 isSwitched 重置为 false ,因此什么也没有发生。删除 isSwitched = false;从初始化状态看看会发生什么 【参考方案1】:问题出在这里:
if (serviceRequestValue == "1" || serviceRequestValue == "1,1" || serviceRequestValue == "14")
serviceRequestValueBool = true;
else
serviceRequestValueBool = false;
您的复选框状态已经改变,但它会重建您的整个有状态小部件,因此上述代码会将其恢复到最后一个状态。您可以为 Switch 创建一个单独的有状态小部件,并让它自行重建以解决此问题。
【讨论】:
【参考方案2】:你应该用 StatefulBuilder 小部件包装你的小部件。
StatefulBuilder(
builder: (context, _setState) => // Your Widget );
【讨论】:
以上是关于开关/复选框未在 setState() 上更新的主要内容,如果未能解决你的问题,请参考以下文章