Flutter - SfCalendar - View not refreshing when changing the view

1.7k Views Asked by At

I am trying to create a view where the user can select the agenda view he wants (day, week, month...). In my appBar, I have created an action icon where the user can select the agenda view he wants. When I change the view, the set state does not refresh the agenda view. I do not find what I am missing.

If you could help, it will be appreciated. Thank you.

import 'package:syncfusion_flutter_calendar/calendar.dart';
import 'package:provider/provider.dart';


class CalendarWidget extends StatefulWidget {

CalendarView viewCalendar;
CalendarController _controller = CalendarController();

CalendarWidget(this.viewCalendar,this._controller, {Key? key}) : super(key: key);

  @override
  State<CalendarWidget> createState() => _CalendarWidgetState(viewCalendar,_controller);
}

class _CalendarWidgetState extends State<CalendarWidget> {
  CalendarView viewCalendar;
  CalendarController _controller;

  @override
  _CalendarWidgetState(this.viewCalendar,this._controller);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        myCalendar(context,viewCalendar,_controller),
        const SizedBox(height: 8.0),
      ],
    );
  }
}

Widget myCalendar (BuildContext context, view,_controler ) {

  final events = Provider.of<EventProvider>(context).events;
  final CalendarController _calendarControler = CalendarController();
  _calendarControler.view = view;

  return SfCalendar(
     view: CalendarView.month,

      // timeSlotViewSettings:
     // const TimeSlotViewSettings(allDayPanelColor: Colors.green),
      controller: _controler,
      _controler.view = view,
    //_controller.view = CalendarView.week,
      showNavigationArrow: true,
      showWeekNumber: true,
      showDatePickerButton: true,
      showCurrentTimeIndicator: true,
      initialSelectedDate: DateTime.now(),
      firstDayOfWeek: 1,
      dataSource: EventDataSource(events),
      onSelectionChanged: (details) {
        final provider = Provider.of<EventProvider>(context, listen: false);

        provider.setDate(details.date!);
      },
      onTap: (details) {
        final provider = Provider.of<EventProvider>(context, listen: false);

        if (provider.selectedDate == details.date) {

          showModalBottomSheet(
            context: context,
            builder: (context) => const TasksWidget(),
          );
        }
      },
      onLongPress: (details) {
        final provider = Provider.of<EventProvider>(context, listen: false);

        provider.setDate(details.date!);

        showModalBottomSheet(
          context: context,
          builder: (context) => const TasksWidget(),
        );
      },
    );
}

class AgendaOrganize extends StatefulWidget {
  const AgendaOrganize ({Key? key}) : super(key : key);
  @override
  _AgendaOrganizeState createState() => _AgendaOrganizeState();
}

class _AgendaOrganizeState extends State<AgendaOrganize> {
  CalendarView viewCalendar = CalendarView.month;
  final CalendarController _controller = CalendarController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        drawer:  const MyMenu(),
        appBar:  AppBar(
          title: const Center(
              child: Text('Agenda')),
          actions: <Widget>[
            PopupMenuButton
              (icon: const Icon(Icons.more_vert_outlined),
              itemBuilder: (BuildContext context) {
              return Menus.choice.map((String choice){
                return PopupMenuItem(
                 value: choice,
                 child: Text(choice));
              }).toList();
              },
            onSelected:
                choiceMade,
            ),

            IconButton(
              icon: const Icon(
                Icons.add_circle_outline,
                color: Colors.white,
              ),
              onPressed: () {
                Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) => const EventEditingPage()));
              },
            ),
          ],),
        body:  CalendarWidget(viewCalendar),

     //TODO //PROBLEME - SI J'AFFICHE PERSISTENTBOTTOMNAVBAR, affiche agenda FOR TODAY
     // bottomNavigationBar: PersistentBottomNavBar(),

    );
    throw UnimplementedError();
  }

  @override
  void setState(VoidCallback fn) {
    viewCalendar = CalendarView.month;
    super.setState(fn);
  }

  void choiceMade(String value) {
    print(value);
    setState(() {
      viewCalendar = CalendarView.month;
    });
  }
}

class Menus {
  static const List<String> choice = <String> [
    'Day', 'Week', 'Work Week', 'Month','Schedule', 'Timeline Day', 'Timeline Week', 'Timeline Work Week'
  ];
}
2

There are 2 best solutions below

3
On BEST ANSWER

Just add a key to the SfCalendar and it's going to change on every setState. Do it like the following:

Widget myCalendar(BuildContext context, CalendarView view) {
  final events = Provider.of<EventProvider>(context).events;
  final CalendarController _calendarControler = CalendarController();
  return SfCalendar(
    key: ValueKey(view),      // <- Here
    view: view,
    ...

Also, the CalendarWidget is passing the state further down to the _CalendarWidgetState itself. The _CalendarWidgetState should use widget.viewCalendar instead.

class CalendarWidget extends StatefulWidget {
  CalendarView viewCalendar;

  CalendarWidget(this.viewCalendar, {Key? key}) : super(key: key);

  @override
  State<CalendarWidget> createState() => _CalendarWidgetState();
}

class _CalendarWidgetState extends State<CalendarWidget> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        myCalendar(context, widget.viewCalendar),
        const SizedBox(height: 8.0),
      ],
    );
  }
}

And here every choice possible:

void choiceMade(String value) {
  setState(() {
    switch (value) {
      case 'Day':
        viewCalendar = CalendarView.day;
        break;
      case 'Week':
        viewCalendar = CalendarView.week;
        break;
      case 'Work Week':
        viewCalendar = CalendarView.workWeek;
        break;
      case 'Month':
        viewCalendar = CalendarView.month;
        break;
      case 'Schedule':
        viewCalendar = CalendarView.schedule;
        break;
      case 'Timeline Day':
        viewCalendar = CalendarView.timelineDay;
        break;
      case 'Timeline Week':
        viewCalendar = CalendarView.timelineWeek;
        break;
      case 'Timeline Work Week':
        viewCalendar = CalendarView.timelineWorkWeek;
        break;
    }
  });
}
1
On

Based on the provided information, we have checked the mentioned issue “Calendar view not updating using Setstate”. View property of the SfCalendar is used to set the initial view of the calendar. For dynamic view changes, we have implemented the view property on the CalendarController. Kindly use that property from the controller for dynamic view changes. Please find the code snippet for dynamic view switching.

 
  @override 
  void initState() { 
    _controller = CalendarController(); 
    super.initState(); 
  } 
 
@override 
Widget build(BuildContext context) { 
  return MaterialApp( 
      home: Scaffold( 
          body: Center( 
    child: SafeArea( 
      child: Column( 
        children: [ 
          Container( 
            height: 550, 
            child: SfCalendar( 
              view: CalendarView.day, 
              controller: _controller, 
            ), 
          ), 
          RaisedButton( 
            onPressed: () => _controller.view = CalendarView.week, 
            child: Text('Change the view'), 
          ), 
        ], 
      ), 
    ), 
  ))); 
} ```


Also please find the breaking changes from the following changelog link. 
 
Changelog link: https://pub.dev/packages/syncfusion_flutter_calendar/changelog 
 
Also, you can use the allowed views property of the calendar for view navigation. Please find the UG from the following link. 
 
UG link: https://help.syncfusion.com/flutter/calendar/date-navigations#allowed-views 
 
We hope that this helps you. Please let us know if you need further assistance.