我正在使用动画列表在我的应用程序上显示实时通知历史记录。我使用订阅来打开一个网络套接字并实时获取更新。
这是包含列表的小部件
void initState() {
super.initState();
_notifications = initialNotificationList; // I get this from the parent
WidgetsBinding.instance!.addPostFrameCallback((_) => _subscribe()); // I open the web socket after rendering the widget
}
// This opens the subscription
Future<bool> _subscribe() async {
try {
_subscription = await ApiService().subscriptions.subscribeNotifications(_onUpdate, _onError);
return true;
} catch (err) {
ToastrService().warning(context, "notificationsSubscriptionError".tr());
return false;
}
}
// Callback when new data arrives
void _onUpdate(List<Notifications> data) {
Notifications newMessage = data.first; // Notifications are ordered in desc chronological order
if ( (_notifications.singleWhereOrNull((el) => el.id == newMessage.id)) == null ) {
setState(() {
_notifications.insert(0, newMessage); // I insert the new notification as first element of the list (my model)
listKey.currentState!.insertItem(0, duration: const Duration(milliseconds: 500)); // I call insert item
});
}
// Animated List
child: AnimatedList(
key: listKey,
initialItemCount: widget.items.length,
scrollDirection: Axis.vertical,
itemBuilder: (context, index, animation) {
// I debugged here and the data that I am passing to the children is correct
return SizeIt(
animation: animation,
widget: NotificationCard(
message: _notifications[index].message,
createdAt: _notifications[index].createdAt,
isRead: _notifications[index].read,
id: _notifications[index].id,
),
);
},
)
这是我的 NotificationCard 类:
class NotificationCard extends StatefulWidget {
final String id;
final String message;
final String createdAt;
final bool isRead;
const NotificationCard({
Key? key,
required this.id,
required this.message,
required this.createdAt,
required this.isRead,
}) : super(key: key);
@override
State<NotificationCard> createState() => _NotificationCardState();
}
class _NotificationCardState extends State<NotificationCard> {
late bool _isRead;
@override
void initState() {
// THIS IS NOT CALLED AFTER insertItem!! I need to hot refresh the app to make it work
// it only calls build
_isRead = widget.isRead;
super.initState();
}
// This function works but only after I hot refresh, otherwise it works but the rendering is wrong
Future<void> setAsRead() async {
if ( !_isRead ) {
try {
bool result = await ApiService().firebase.setNotificationAsRead(widget.id);
setState(() {
_isRead = result;
});
} catch (onError) {
ToastrService().error(context, onError.toString());
}
}
}
@override
Widget build(BuildContext context) {
// If I print all the widget. variables, the values are right. BUILD IS CALLED WHEN I CALL insertItem. After hot reload, build is called after initState as it is supposed to do
return Container(
child: GestureDetector(
onTap: this.setAsRead,
child: Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
elevation: 2.0,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 6.5.w),
padding: EdgeInsets.symmetric(vertical: 1.5.h),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// InitState is not called even in this child:
NotificationsTimestamp(timestamp: widget.createdAt),
_isRead ? Container() :
Container(
child: Icon(
SFSymbols.circle_fill,
size: 12.0.sp,
color: Styles.primary,
),
),
],
),
Container(
margin: EdgeInsets.only(top: 1.0.h),
child: AutoSizeText(
widget.message,
style: Styles.NotificationText,
maxLines: 4,
minFontSize: 11.0,
),
),
],
),
),
),
),
);
}
}
不知何故,当一个新的通知到达时,动画工作并且项目被添加了正确的 widget.text,但是 _isRead 和 createdAt 是错误的!难道我做错了什么?