【问题标题】:How to show Event on Table Calendar using my API on flutter如何在 Flutter 上使用我的 API 在表日历上显示事件
【发布时间】: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 中的示例值

【问题讨论】:

标签: json api flutter dart android-calendar


【解决方案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;
    }
    

    希望你明白了!

    【讨论】:

      猜你喜欢
      • 2020-06-02
      • 1970-01-01
      • 2012-12-21
      • 2021-02-14
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多