好了,伙计们,现在我将向您展示我发现的使用表日历显示来自 api 的事件和卡片的方法。
我什至不需要说这是我发现事物的方式,请随意添加新事物并在这里提供提示。所以我们走吧。
首先,我们将显示日历事件,但在这一步中仅显示标记,如果您在这里,来自 api 的数据必须包含日期,在我的例子中,日期作为字符串出现,所以让我们为它们创建模型
import 'dart:convert';
class EventsModel {
final String dataDoJob;
EventsModel({
required this.dataDoJob,
});
Map<String, dynamic> toMap() {
return {
'data_acao': dataDoJob,
};
}
factory EventsModel.fromMap(Map<String, dynamic> map) {
return EventsModel(
dataDoJob: map['data_acao'],
);
}
String toJson() => json.encode(toMap());
factory EventsModel.fromJson(String source) => EventsModel.fromMap(json.decode(source));
}
这是我的模型,正如你所看到的,我刚刚获取日期。现在让我们使用 get 方法从 api 检索此数据,我使用 getConnect 但您可以使用您想要的 http 客户端。
@override
Future<List<EventsModel>> getEvents() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
final int? id = sharedPreferences.getInt("idInfluencer");
final String token = sharedPreferences.getString("token") ?? "";
final Response result = await _restClient.get<List<EventsModel>>(
"/job_acoes?influenciador_id=${id.toString()}",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
}, decoder: (data) {
if (data != null) {
return data
.map<EventsModel>((event) => EventsModel.fromMap(event))
.toList();
}
return <EventsModel>[];
});
if (result.hasError) {
print(result.statusCode);
throw "Erro ao buscar dados";
}
print(result.body);
print(result.statusCode);
return result.body;
}
做得好,我们已经有了一个日期列表,但在我的例子中,它们是字符串,所以我必须转换它们,如下所示:
final events = await _jobsServices.getEvents();
//final dateFormat = DateFormat("yyyy-MM-dd");
final eventsConvert =
events.map((date) => (DateTime.parse(date.dataDoJob))).toList();
eventsList.assignAll(eventsConvert);
print("Lista de eventos : $eventsList");
streamController.add(events);
在第一行,我将列表保存在一个名为 events 的变量中,在下面我使用 map 方法将字符串转换为日期时间,并将它们添加到我创建的空列表中,然后逐步执行以下操作:一个空列表,并将转换后的数据添加到其中,就像我上面所做的那样,我的空列表称为 eventsList
完成后,我们将在表日历中显示此列表
class CalendarWidget extends GetView<HomeController> {
const CalendarWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StreamBuilder<List<EventsModel>>(
stream: controller.streamController.stream,
builder: (context, snapshot) {
return Obx(() {
return TableCalendar(
eventLoader: (day) => controller.eventsList.where((event) => isSameDay(event,day)).toList(), //THIS IS IMPORTANT
focusedDay: controller.focusedDay.value,
firstDay: DateTime(2019),
lastDay: DateTime(2050),
headerStyle:
const HeaderStyle(formatButtonVisible: false), //WEEK VISIBLE
locale: 'pt_BR',
daysOfWeekVisible: true,
calendarFormat: controller.format.value,
onFormatChanged: (CalendarFormat _format) =>
controller.calendarFormat(_format),
onDaySelected: (DateTime userSelectedDay, DateTime focusedDay) =>
controller.selectedDay(userSelectedDay, focusedDay),
calendarStyle: CalendarStyle(
selectedTextStyle: const TextStyle(color: Colors.white),
isTodayHighlighted: true,
selectedDecoration: BoxDecoration(
color: context.buttomThemeClicled,
shape: BoxShape.circle)),
selectedDayPredicate: (DateTime date) {
return isSameDay(controller.focusedDay.value, date);
},
);
});
});
}
}
记住我使用的是无状态小部件,所以我需要一个状态管理器,并且我使用 getx,所以它有一个涉及整个日历的 obx。
在事件加载器中,有些人有疑问,您可以在其上传递列表或地图,在我的例子中,为了简单起见,我正在使用列表,请注意,在事件加载器中,我正在执行简单的过滤,比较我的日历的日期与我从 api 获取的日期,很简单不是吗?通过执行此操作,您的基于 api 的书签将已经显示。啊,一个细节,只要 api 发生变化,流构建器就会重做我的小部件,如果你不知道如何使用它,这个视频将解释:https://www.youtube.com/watch?v=BBelgajHgzY https://www.youtube.com/watch?v=BBelgajHgzY
现在让我们进入基于天数的事件显示部分,我的事件将显示在这样的卡片上:
所以我将它构建在与我的主页不同的页面上,这部分很重要,因为您的代码将变得更容易和更清晰,完成小部件后,我们将在屏幕上显示它们,如下所示:
child: Obx(() {
return ListView(
scrollDirection: Axis.vertical,
children: controller.cards
.map(
(c) => AgendaCards(
bottomPosition: 80,
leftPositioned: 260,
maxRadius: 5,
rightPositioned: 5,
secondMaxradius: 5,
topPositioned: 20,
model: c,
),
)
.toList(),
);
}));
名为日历卡的小部件无非是上面照片中的卡片,在它上面我要求了一个名为
final JobsDescriptionCardsModel model;
并在构造函数中调用他
AgendaCards({
required this.leftPositioned,
required this.rightPositioned,
required this.topPositioned,
required this.bottomPosition,
required this.maxRadius,
required this.secondMaxradius,
required this.model, //HERE
Key? key,
}) : super(key: key);
所以让我们创建这个模型
class JobsDescriptionCardsModel {
final String descricaoJob;
final String dataDoJob;
final String horarioDoJob;
final int jobId;
final String nome;
JobsDescriptionCardsModel({
required this.descricaoJob,
required this.dataDoJob,
required this.horarioDoJob,
required this.jobId,
required this.nome,
});
Map<String, dynamic> toMap() {
return {
'descricaoJob': descricaoJob,
'dataDoJob': dataDoJob,
'horarioDoJob': horarioDoJob,
'jobId': jobId,
'nome': nome,
};
}
factory JobsDescriptionCardsModel.fromMap(Map<String, dynamic> map) {
return JobsDescriptionCardsModel(
descricaoJob: map['descricao'] ?? "",
dataDoJob: map['data_acao'] ?? "",
horarioDoJob: map['hora_inicial_acao'],
jobId: map['job_acao_id'] ?? 0,
nome: map['job'] ["cliente"] ["nome"] ?? "",
);
}
String toJson() => json.encode(toMap());
factory JobsDescriptionCardsModel.fromJson(String source) => JobsDescriptionCardsModel.fromMap(json.decode(source));
}
并在 api 上获取它
@override
Future<List<JobsDescriptionCardsModel>> getJobsDescrition() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
final int? id = sharedPreferences.getInt("idInfluencer");
final String token = sharedPreferences.getString("token") ?? "";
final result = await _restClient.get<List<JobsDescriptionCardsModel>>(
"/job_acoes?influenciador_id=${id.toString()}",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
}, decoder: (data) {
if (data != null) {
return data
.map<JobsDescriptionCardsModel>(
(j) => JobsDescriptionCardsModel.fromMap(j))
.toList();
}
return <JobsDescriptionCardsModel>[];
});
if (result.hasError) {
throw ("erro ao buscar dados");
}
return result.body ?? <JobsDescriptionCardsModel>[];
}
API 给了我一个重要的列表。有了列表,我们将了解台历的概念。要继续并了解将要做什么,我建议您观看此视频:
完成日历的配置后,我相信您已经注意到,当您单击日期并打印具有日期数据的变量时,您会注意到表日历为您提供了日期时间作为返回,并且如果您有在我的模型中引起注意,我还有一个来自 api 的日期,知道我们只需要根据表日历数据过滤来自 api 的列表,如下所示:
首先像我们之前一样创建一个空列表和一个将被过滤的列表:
//LISTA DE JOBS CARDS
final cards = <JobsDescriptionCardsModel>[].obs;
//LISTA FILTRADA
var cardsFiltered = <JobsDescriptionCardsModel>[];
空列表将填充 api 数据,如下所示:
final jobsCards = await _jobsServices.getJobsDescrition();
cards.assignAll(jobsCards);
有了现有的填充列表,我们将根据 api 日期过滤此列表,如下所示:
cardsFiltered = jobsCards;
var novaLista = cardsFiltered.where((model) {
return model.dataDoJob
.toString()
.contains(focusedDay.value.toString().substring(1, 10));
});
看到吗,首先我将填充的列表分配给一个新列表,然后我根据我的模型仅在包含我字符串的部分中过滤此列表,与我单击它时记住的日期的变量进行比较?也转换为字符串,因为表日历为我提供了日期以及我认为是时间信息的其他数字,我仅从索引 1 到 10 获取了数据,这将准确地给出变量中包含的日期。完成后,表日历有一个名为 onDaySelected 的属性,它将显示我们的过滤列表,如下所示:
selectedDay(DateTime selectedDayInfo, DateTime focusDayInfo) {
userSelectedDay.value = selectedDayInfo;
focusedDay.value = focusDayInfo;
print(userSelectedDay.value);
print(focusedDay.value);
print("Lista de eventos 2 ${eventsList}");
var novaLista = cardsFiltered.where((model) {
return model.dataDoJob
.toString()
.contains(focusedDay.value.toString().substring(0, 10));
});
cards.assignAll(novaLista);
我在控制器中创建了这个单独的函数,并在表日历中调用它,如下所示:
onDaySelected: (DateTime userSelectedDay, DateTime focusedDay) =>
controller.selectedDay(userSelectedDay, focusedDay),
完成后,您的日历将已经显示默认标记和基于您构建的小部件的卡片,请记住使用您通过构造函数请求的模型将数据传递到您的卡片,因为它包含 api 数据。我希望我有帮助,我对谷歌翻译英语感到抱歉