我正在开发一个 Flutter 应用程序,它使用 Rive 动画 作为复选框。
虽然点击时复选框视觉上可以正确切换,但编程状态不会反映这些更改。具体来说,
submittedMissions
列表无法正确更新 - 当取消选中复选框时,它无法删除 ID,从而导致应用程序逻辑中的状态表示不准确。
尽管取消选中 UI 中的两个框,应用程序仍然报告 2 个框已选中,这表明状态管理失败:
相反,用 Flutter 的原生 Checkbox 小部件替换 Rive 的复选框可以解决此问题,强调 Rive 如何处理状态更改的特定问题:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rive/rive.dart';
void main() => runApp(MaterialApp(home: MissionListScreen(), debugShowCheckedModeBanner: false));
class MissionListScreen extends StatefulWidget {
@override
_MissionListScreenState createState() => _MissionListScreenState();
}
class _MissionListScreenState extends State<MissionListScreen> {
List<MissionItem> missions = [
MissionItem(missionId: '1', missionName: 'Mission 1'),
MissionItem(missionId: '2', missionName: 'Mission 2'),
MissionItem(missionId: '3', missionName: 'Mission 3'),
];
List<String> submittedMissions = [];
@override
void initState() {
super.initState();
loadRiveFiles();
}
void loadRiveFiles() async {
for (var mission in missions) {
final data = await rootBundle.load('assets/checkbox.riv');
final file = RiveFile.import(data);
final artboard = file.mainArtboard;
var controller = StateMachineController.fromArtboard(artboard, 'State Machine 1');
if (controller != null) {
artboard.addController(controller);
mission.checkButtonInput = controller.findInput<bool>('Tap');
mission.checkButtonArtboard = artboard;
mission.checkButtonInput?.value = submittedMissions.contains(mission.missionId);
}
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Text('There are ${submittedMissions.length} boxes checked.', style: TextStyle(fontSize: 20, fontWeight: FontWeight bold)),
Expanded(
child: ListView.builder(
itemCount: missions.length,
itemBuilder: (context, index) => buildMissionListTile(missions[index]),
),
),
],
),
);
}
Widget buildMissionListTile(MissionItem mission) {
return ListTile(
title: Text(mission.missionName),
trailing: GestureDetector(
onTap: () => toggleMission(mission),
child: SizedBox(height: 32, width: 32, child: Rive(artboard: mission.checkButtonArtboard!)),
),
);
}
void toggleMission(MissionItem mission) {
bool currentState = mission.checkButtonInput?.value ?? false;
setState(() {
mission.checkButtonInput?.value = !currentState;
if (currentState) {
submittedMissions.removeWhere((id) => id == mission.missionId);
} else {
if (!submittedMissions.contains(mission.missionId)) {
submittedMissions.add(mission.missionId);
}
}
});
print("Submitted Missions: $submittedMissions"); // Debugging
}
}
class MissionItem {
final String missionId;
final String missionName;
SMIInput<bool>? checkButtonInput;
Artboard? checkButtonArtboard;
MissionItem({required this.missionId, required this.missionName});
}
如何确保 Flutter 中由 Rive 动画触发的状态变化被正确识别和处理?
尽管有视觉指示表明复选框正在切换,但内部状态并未反映这些变化。
您可以从 Rive 官方网站 或从 Google Drive 下载此 rive (.riv) 文件。
不要忘记将上述文件添加到您的资产文件夹中并更新
pubspec.yaml
文件。
您以错误的方式更新数据,每次点击开关时都需要更新
missions
,因为您的 buildMissionListTile
与 missions
一起使用。试试这个:
Widget buildMissionListTile(MissionItem mission, int index) {
return ListTile(
title: Text(mission.missionName),
trailing: GestureDetector(
onTap: () => toggleMission(mission, index),
child: SizedBox(height: 32, width: 32, child: Rive(artboard: mission.checkButtonArtboard!)),
),
);
}
void toggleMission(MissionItem mission,int index) {
bool currentState = mission.checkButtonInput?.value ?? false;
setState(() {
mission.checkButtonInput?.value = !currentState;
MissionItem newMission= mission;
if (currentState) {
submittedMissions.removeWhere((id) => id == mission.missionId);
} else {
if (!submittedMissions.contains(mission.missionId)) {
submittedMissions.add(mission.missionId);
}
}
missions.removeAt(index);
missions.insert(index, newMission);
});
print("Submitted Missions: $submittedMissions"); // Debugging
}
在这种方法中,我将
index
传递给 toggleMission
,并在每次 missions
有新状态时更新 mission
。