如何在 Flutter 上使用我的 API 在表日历上显示事件
Posted
技术标签:
【中文标题】如何在 Flutter 上使用我的 API 在表日历上显示事件【英文标题】:How to show Event on Table Calendar using my API on flutter 【发布时间】:2021-08-24 05:02:50 【问题描述】:我有用于显示事件日历的 UI,我需要显示来自我的 API 的事件。但我不知道该怎么做。我尝试更改 _event 上的列表,但没有响应。我需要在日历上显示它,这样我的公司日历才能显示该事件。
这是我的 UI 日历
import 'package:intl/intl.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:urus_flutter/persentation/custom_color.dart';
import 'package:urus_flutter/persentation/custom_text_style.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Calender extends StatefulWidget
@override
State<StatefulWidget> createState() => CalenderState();
class CalenderState extends State<Calender>
CalendarController _controller;
Map<DateTime, List<dynamic>> _events;
List<dynamic> _selectedEvents;
DateTime _selectedDate;
SharedPreferences prefs;
@override
void initState()
super.initState();
_controller = CalendarController();
_events =
DateTime(2021, 6, 22) : ['Meeting URUS', 'Testing Danai Mobile', 'Weekly Report', 'Weekly Meeting'],
DateTime(2021, 6, 25) : ['Weekly Testing'],
DateTime(2021, 6, 4) : ['Weekly Testing'],
DateTime(2021, 6, 11) : ['Weekly Testing'],
DateTime(2021, 6, 18) : ['Weekly Testing'],
;
Map<String, dynamic> encodeMap(Map<DateTime, dynamic> map)
Map<String, dynamic> newMap = ;
map.forEach((key, value)
newMap[key.toString()] = map[key];
);
return newMap;
Map<DateTime, dynamic> decodeMap(Map<String, dynamic> map)
Map<DateTime, dynamic> newMap = ;
map.forEach((key, value)
newMap[DateTime.parse(key)] = map[key];
);
return newMap;
Widget build(BuildContext context)
return Scaffold(
body: Stack(
children: [
ListView(
padding: EdgeInsets.only(left: 16, right: 16, top: 52, bottom: 126),
children: [
Text("Kalender Kegiatan",
style: CustomTextStlye.proxima_bold_18_black,),
Container(
child: Padding(
padding: const EdgeInsets.only(top: 28.0),
child: Text("Kalender Anda",
style: CustomTextStlye.proxima_bold_16_black,),
),
),
SizedBox(
height: 20,
),
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5.0),
boxShadow: [
BoxShadow(
offset: Offset(0, -1),
color: CustomColor.border_grey,
blurRadius: 3.0,
spreadRadius: 1.0)
]
),
child: TableCalendar(
initialCalendarFormat: CalendarFormat.month,
calendarStyle: CalendarStyle(
todayColor: Color(0x9429AAE1),
todayStyle: CustomTextStlye.proxima_bold_12_white,
selectedColor: Color(0xFF29AAE1),
selectedStyle: CustomTextStlye.proxima_bold_12_white,
weekdayStyle: CustomTextStlye.proxima_bold_12_black,
weekendStyle: CustomTextStlye.proxima_bold_12_red,
unavailableStyle: CustomTextStlye.proxima_bold_12,
holidayStyle: CustomTextStlye.proxima_bold_12_red,
markersColor: Color(0xFFA2CD3A),
),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonVisible: false,
titleTextStyle: CustomTextStlye.proxima_bold_14_black,
),
availableCalendarFormats: const CalendarFormat.month: '',,
startingDayOfWeek: StartingDayOfWeek.monday,
calendarController: _controller,
events: _events,
onDaySelected: (date, events,holidays)
setState(()
_selectedEvents = events;
_selectedDate = date;
);
,
),
)
],
),
),
Container(
child:Padding(
padding: const EdgeInsets.only(top: 28.0),
child: Text("Kegiatan Anda",
style: CustomTextStlye.proxima_bold_16_black,),
),
),
Container(
child: _selectedEvents != null ? Column(
children: List.generate(_selectedEvents.length, (index) =>
Container(
padding: const EdgeInsets.all(8.0),
child: Container(
height: MediaQuery.of(context).size.height/15,
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Color.fromRGBO(228, 228, 228, 1)))
),
child:
Center(
child:
Container(child:
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 10.0),
height: MediaQuery.of(context).size.height/10,
decoration: BoxDecoration(
border: Border.all(color:Color(0xFF29AAE1)),
color:Color(0xFF29AAE1),
borderRadius: BorderRadius.circular(3.0),
),
child: Text(DateFormat('d').format(_selectedDate),
style: CustomTextStlye.proxima_bold_18_white,
),
),
),
Text(_selectedEvents[index],
style: CustomTextStlye.proxima_bold_14_black,
),
],
),
)
),
),
),
),
) : Container(),
)
],
),
],
),
);
这是我的 eventCalendarService.dart
import 'dart:convert';
import 'dart:io';
import 'package:http/io_client.dart';
import 'package:urus_flutter/data/eventController.dart';
import 'package:urus_flutter/data/model/base/event_calendar.dart';
Future<List<Event_Calendar>> fetchEventCalendar(String id, int company_id, String date) async
String requestBody = '';
print(requestBody);
final ioc = new HttpClient();
ioc.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
final http = new IOClient(ioc);
final response = await http.get(
getStringUrl+'staffs/GetCalendar?companyid=$company_id&month=$date',
);
print(response.statusCode);
print(response.body);
if (response.statusCode == 200)
var parsed = jsonDecode(response.body);
return List<Event_Calendar>.from(parsed.map((model) => Event_Calendar.fromJson(model)));
else
throw Exception(response.body);
这里是我的模型 event_calendar.dart
class Event_Calendar
final String id;
final String type;
final String date;
final String event_name;
final int company_id;
Event_Calendar(
this.id,
this.type,
this.date,
this.event_name,
this.company_id,
);
factory Event_Calendar.fromJson(Map<String, dynamic> json)
return Event_Calendar(
id: json['id'] as String,
type: json['type'] as String,
date: json['date'] as String,
event_name: json['event_name'] as String,
company_id: json['company_id'] as int,
);
我希望任何人都可以回答我如何在我的 API 中显示 _events。谢谢你。这是我的 API 中的示例值
【问题讨论】:
查看这个帖子***.com/questions/60276303/… 我试过了,但对我来说是错误的。结构完全不同T^T 【参考方案1】:伙计们,现在我将向您展示我发现的使用表格日历显示来自 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
现在让我们进入基于天数的事件显示部分,我的事件将显示在这样的卡片上:
所以我将它构建在与我家不同的页面上,这部分很重要,因为您的代码将更简单、更清晰,完成小部件后,我们将在屏幕上显示它们,如下所示:
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 给了我一个重要的列表。有了列表,我们将进入表格日历的概念。要继续并了解将要做什么,我建议您观看此视频:https://www.youtube.com/watch?v=HKuzPQUV21Y&t=291s
完成日历的配置后,相信您已经注意到,当您单击日期并打印具有日期数据的变量时,您会注意到表格日历为您提供了日期时间作为返回,并且如果你在我的模型中呈现了注意力,我也有一个来自 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 数据。我希望我有帮助,我很抱歉谷歌翻译英语
【讨论】:
【参考方案2】:_event
未在 table_calendar
的较新版本中使用。您可以使用eventLoader
,它将在日历上显示您的活动。
例子:
日历小部件如下,
TableCalendar<Event>(
firstDay: kFirstDay,
lastDay: kLastDay,
focusedDay: _focusedDay,
selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
eventLoader: _getEventsForDay, // this will load events on calendar
),
_getEventsForDay
方法如下,
List<Event> _getEventsForDay(DateTime day)
return kEvents[day] ?? [];
kEvents
(需要在日历上标注的事件列表)如下,如果有事件列表就不需要创建了。
final kEvents = LinkedHashMap<DateTime, List<Event>>(
equals: isSameDay,
hashCode: getHashCode,
)..addAll(_kEventSource);
final _kEventSource = Map.fromIterable(List.generate(50, (index) => index),
key: (item) => DateTime.utc(kFirstDay.year, kFirstDay.month, item * 5),
value: (item) => List.generate(
item % 4 + 1, (index) => Event('Event $item | $index + 1')))
..addAll(
kToday: [
Event('Event 1'),
Event('Event 2'),
],
);
Event
类如下,(也可以随意制作)
class Event
final String title;
const Event(this.title);
@override
String toString() => title;
希望你明白了!
【讨论】:
以上是关于如何在 Flutter 上使用我的 API 在表日历上显示事件的主要内容,如果未能解决你的问题,请参考以下文章
如何打印几个标记google map api 0.5.7 Flutter