如何使用我的 flutter API 在表格日历上显示事件

莎拉S*_*rah 6 api json android-calendar dart flutter

我有用于显示事件日历的 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(),
              )
            ],
          ),
        ],
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 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);
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的模型 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,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

我希望任何人都可以给我关于如何向我的 API 显示 _events 的答案。谢谢。这是我的 API 中的示例值

在此输入图像描述

fla*_*ack 4

好了,伙计们,现在我将向你们展示我发现的使用表日历显示来自 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));
}
Run Code Online (Sandbox Code Playgroud)

这是我的模型,正如你所看到的,我刚刚获取日期。现在让我们使用 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;
  }
Run Code Online (Sandbox Code Playgroud)

做得好,我们已经有了一个日期列表,但在我的例子中,它们是字符串,所以我必须转换它们,如下所示:

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);
Run Code Online (Sandbox Code Playgroud)

在第一行,我将列表保存在一个名为 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);
              },
            );
          });
        });
  }
}
Run Code Online (Sandbox Code Playgroud)

记住我使用的是无状态小部件,所以我需要一个状态管理器,并且我使用 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(),
                          );
                        }));
Run Code Online (Sandbox Code Playgroud)

名为日历卡的小部件无非是上面照片中的卡片,在它上面我要求了一个名为

final JobsDescriptionCardsModel model;
Run Code Online (Sandbox Code Playgroud)

并在构造函数中调用他

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);
Run Code Online (Sandbox Code Playgroud)

所以让我们创建这个模型

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));
}
Run Code Online (Sandbox Code Playgroud)

并在 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>[];
  }
Run Code Online (Sandbox Code Playgroud)

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>[];
Run Code Online (Sandbox Code Playgroud)

空列表将填充 api 数据,如下所示:

final jobsCards = await _jobsServices.getJobsDescrition();
        cards.assignAll(jobsCards);
Run Code Online (Sandbox Code Playgroud)

有了现有的填充列表,我们将根据 api 日期过滤此列表,如下所示:

cardsFiltered = jobsCards;

        var novaLista = cardsFiltered.where((model) {
          return model.dataDoJob
              .toString()
              .contains(focusedDay.value.toString().substring(1, 10));
        });
Run Code Online (Sandbox Code Playgroud)

看到了吗,首先我将填充的列表分配给一个新列表,然后我根据我的模型仅在包含我字符串的部分中过滤此列表,与我单击它时记住的日期的变量进行比较?也转换为字符串,因为表日历为我提供了日期以及我认为是时间信息的其他数字,我仅从索引 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);
Run Code Online (Sandbox Code Playgroud)

我在控制器中创建了这个单独的函数,并在表日历中调用它,如下所示:

onDaySelected: (DateTime userSelectedDay, DateTime focusedDay) =>
                  controller.selectedDay(userSelectedDay, focusedDay),
Run Code Online (Sandbox Code Playgroud)

当您的日历已经显示默认标记和基于您构建的小部件的卡片时,请记住使用您通过构造函数请求的模型将数据传递到您的卡片,因为它包含 api 数据。我希望我有帮助,我对谷歌翻译英语感到抱歉