r_calendar 0.1.7

  • Readme
  • Changelog
  • Example
  • Installing
  • 79

r_calendar #

pub package

A new Flutter package about calendar,you can use this design the calendar and support single or multiple selected.

中文点此 #

1.Getting Started. #

  • use plugin: add this code in pubspec.yaml
dependencies:
  r_calendar: last version
  • add the packages to your file.
import 'package:r_calendar/r_calendar.dart';

  • radio select
///
/// [selectedDate] will default selected one
/// [isAutoSelect] when the page view change will change month to auto select same day.
    RCalendarController controller= RCalendarController.single(
                    selectedDate: DateTime.now(),
                    isAutoSelect: true,);
  • check select
///
/// [selectedDates] will default selected more.
/// [isDispersion] will selected continuity dateTime.
    RCalendarController controller = RCalendarController.multiple(
                    selectedDates: [
                        DateTime(2019, 12, 1),
                        DateTime(2019, 12, 2),
                        DateTime(2019, 12, 3),
                    ],
                    isDispersion: true);
  • value change listener
///
/// addListener to observe value change
    RCalendarController controller = RCalendarController.multiple(...)
    addListener((){
    // controller.isMultiple

    // single selected
    // controller.isAutoSelect
    // controller.selectedDate;

    // multiple selected
    // controller.selectedDates;
    // controller.isDispersion;

    // mode month/week
    // controller.mode
    });
  • custom your widget

class MyRCalendarCustomWidget extends RCalendarCustomWidget {

  // If you want to change first day is Monday ,you can change [MaterialLocalizations.firstDayOfWeekIndex]
  // SUM MON TUE WED THU FRI SUT
  //build your week header
  @override
  List<Widget> buildWeekListWidget(BuildContext context,MaterialLocalizations localizations){...};

  // 1 2 3 4 5 6 7
  //build normal dateTime
  @override
  Widget buildDateTime(BuildContext context, DateTime time, List<RCalendarType> types){...};

  //   <  2019 year 11 month >
  //build year and month and left 、 right Indicator
  @override
  Widget buildTopWidget(BuildContext context, RCalendarController controller){...};


  //is unable will not have tap events
  @override
  bool isUnable(DateTime time, bool isSameMonth){...};

  //Click intercept. When it returns true to intercept, the selected date will not be changed
  @override
  FutureOr<bool> clickInterceptor(BuildContext context, DateTime dateTime){...};

  //Height of child view
  @override
  double get childHeight=>{...};
}

2.Use this #

import 'package:flutter/material.dart';
import 'package:r_calendar/r_calendar.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  RCalendarController controller;

  @override
  void initState() {
    super.initState();
    controller = RCalendarController.multiple(selectedDates: [
      DateTime(2019, 12, 1),
      DateTime(2019, 12, 2),
      DateTime(2019, 12, 3),
    ]);
//    controller = RCalendarController.single(selectedDate: DateTime.now(),isAutoSelect: true);
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: RCalendarWidget(
               controller: controller,
               customWidget: DefaultRCalendarCustomWidget(),
               firstDate: DateTime(1970, 1, 1),
               lastDate: DateTime(2055, 12, 31),
             ),
    );
  }
}

3.Expand Data(update by v0.1.6 ) #

/// initial
    RCalendarController<List<DateTime>> controller =  RCalendarController.single(
    initialData: [
            DateTime.now(),
            DateTime.now().add(Duration(days: 1)),
            DateTime.now().add(Duration(days: 2)),
          ]
    );

/// if you want to update expand data ,use it.
    controller.data = [....];

/// you can use it get the controller in RCalendarCustomWidget

class MyRCalendarCustomWidget extends RCalendarCustomWidget {
///...
  @override
  Widget buildDateTime(
      BuildContext context, DateTime time, List<RCalendarType> types) {

    // new
    RCalendarController<List<DateTime>> controller =RCalendarMarker.of(context).notifier;
    // new

    //...
   }
///...

[0.1.7] - Fix the bugs in aggregate selection #

[0.1.6] - add expand data in controller #

[0.1.5] - format #

[0.1.4] - add week view . #

[0.1.3] - remove buildMonthYear 、left and right , add build top widget. #

[0.1.2] - add single and multiple selected to packages. #

[0.1.1] - fix listener data not change and add monthDate to controller. #

[0.1.0] - release #

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:r_calendar/r_calendar.dart';
import 'package:r_calendar_example/l10n/s.dart';
import 'package:intl/intl.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      localizationsDelegates: [
        S.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate
      ],
      supportedLocales: [Locale('zh', ''), Locale('en', '')],
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  RCalendarController<List<DateTime>> controller;

  @override
  void initState() {
    super.initState();
    controller =
//    RCalendarController.multiple(
//      selectedDates: [
//        DateTime(2019, 12, 1),
//        DateTime(2019, 12, 2),
//        DateTime(2019, 12, 3),
//      ],
//      isDispersion: false,
//    )
        RCalendarController.single(isAutoSelect: true,
            //mark day
            initialData: [
          DateTime.now(),
          DateTime.now().add(Duration(days: 1)),
          DateTime.now().add(Duration(days: 2)),
        ]
//      selectedDate: DateTime.now(),
            )
          ..addListener(() {
            // controller.isMultiple

            // single selected
            // controller.isAutoSelect
            // controller.selectedDate;

            // multiple selected
            // controller.selectedDates;
            // controller.isDispersion;
          });
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        decoration: BoxDecoration(
          color: Colors.grey[200],
        ),
        margin: EdgeInsets.symmetric(
          horizontal: 8,
        ),
        child: RCalendarWidget(
          controller: controller,
          customWidget: MyRCalendarCustomWidget(),
          firstDate: DateTime(1970, 1, 1),
          lastDate: DateTime(2055, 12, 31),
        ),
//        child: RecordDatePicker(
//          selectedDate: DateTime.now(),
//          firstDate: DateTime(1970, 1, 1),
//          lastDate: DateTime(2055, 12, 31),
//          children: List.generate(20, (index)=>ListTile(
//            title: Text('data $index'),
//          )),
//        ),
      ),
      floatingActionButton: Row(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          FloatingActionButton(
            onPressed: () {
              setState(() {
                if (controller.isMonthMode) {
                  controller.mode = RCalendarMode.week;
                } else {
                  controller.mode = RCalendarMode.month;
                }
              });
            },
            tooltip: controller.isMonthMode
                ? S.of(context).month
                : S.of(context).week,
            child: Text(
              controller.isMonthMode ? S.of(context).month : S.of(context).week,
              style: TextStyle(
                color: Colors.white,
              ),
              maxLines: 1,
              semanticsLabel: controller.isMonthMode
                  ? S.of(context).month
                  : S.of(context).week,
            ),
          ),
          SizedBox(
            width: 20,
          ),
          FloatingActionButton(
            onPressed: () {
              setState(() {
                controller.isMultiple = !controller.isMultiple;
              });
            },
            tooltip: controller.isMultiple
                ? S.of(context).more
                : S.of(context).single,
            child: Text(
              controller.isMultiple ? S.of(context).more : S.of(context).single,
              style: TextStyle(
                color: Colors.white,
              ),
              maxLines: 1,
              semanticsLabel: controller.isMultiple
                  ? S.of(context).more
                  : S.of(context).single,
            ),
          ),
          SizedBox(
            width: 20,
          ),
          ...controller.isMultiple
              ? [
                  FloatingActionButton(
                    onPressed: () {
                      setState(() {
                        controller.isDispersion = !controller.isDispersion;
                      });
                    },
                    tooltip: controller.isDispersion
                        ? S.of(context).alone
                        : S.of(context).together,
                    child: Text(
                      controller.isDispersion
                          ? S.of(context).alone
                          : S.of(context).together,
                      style: TextStyle(
                        color: Colors.white,
                      ),
                      maxLines: 1,
                      semanticsLabel: controller.isDispersion
                          ? S.of(context).alone
                          : S.of(context).together,
                    ),
                  ),
                ]
              : [
                  FloatingActionButton(
                    onPressed: () {
                      setState(() {
                        controller.isAutoSelect = !controller.isAutoSelect;
                      });
                    },
                    tooltip: controller.isAutoSelect
                        ? S.of(context).automatic
                        : S.of(context).manual,
                    child: Text(
                      controller.isAutoSelect
                          ? S.of(context).automatic
                          : S.of(context).manual,
                      style: TextStyle(
                        color: Colors.white,
                      ),
                      maxLines: 1,
                      semanticsLabel: controller.isAutoSelect
                          ? S.of(context).automatic
                          : S.of(context).manual,
                    ),
                  ),
                  SizedBox(
                    width: 20,
                  ),
                  FloatingActionButton(
                    onPressed: () {
                      setState(() {
                        controller.selectedDate =
                            controller.selectedDate.add(Duration(days: 1));
                      });
                    },
                    tooltip: S.of(context).add,
                    child: Icon(Icons.add),
                  ),
                  SizedBox(
                    width: 20,
                  ),
                  FloatingActionButton(
                    onPressed: () {
                      setState(() {
                        controller.selectedDate =
                            controller.selectedDate.subtract(Duration(days: 1));
                      });
                    },
                    tooltip: S.of(context).reduce,
                    child: Icon(Icons.remove),
                  )
                ],
        ],
      ),
    );
  }
}

class MyRCalendarCustomWidget extends RCalendarCustomWidget {
  @override
  Widget buildDateTime(
      BuildContext context, DateTime time, List<RCalendarType> types) {
    // new
    RCalendarController<List<DateTime>> controller =
        RCalendarMarker.of(context).notifier;
    // new
    TextStyle childStyle;
    BoxDecoration decoration;
    if (types.contains(RCalendarType.disable) ||
        types.contains(RCalendarType.differentMonth)) {
      childStyle = TextStyle(
        color: Colors.grey[400],
        fontSize: 18,
      );
      decoration = BoxDecoration();
    }
    if (types.contains(RCalendarType.normal)) {
      childStyle = TextStyle(
        color: Colors.black,
        fontSize: 18,
      );
      decoration = BoxDecoration();
    }

    if (types.contains(RCalendarType.today)) {
      childStyle = TextStyle(
        color: Colors.blue,
        fontSize: 18,
      );
    }

    if (types.contains(RCalendarType.selected)) {
      childStyle = TextStyle(
        color: Colors.white,
        fontSize: 18,
      );
      decoration = BoxDecoration(
        shape: BoxShape.circle,
        color: Colors.blue,
      );
    }
    Widget child = Container(
        decoration: decoration,
        alignment: Alignment.center,
        child: Text(
          time.day.toString(),
          style: childStyle,
        ));
    //get mark day
    if (controller.data
        .where((m) =>
            time.year == m.year && time.month == m.month && time.day == m.day)
        .isNotEmpty) {
      child = Stack(
        children: <Widget>[
          child,
          Positioned(
              bottom: 0,
              left: 0,
              right: 0,
              child: Icon(
                Icons.star,
                size: 14,
                color: Colors.grey,
              )),
        ],
      );
    }
    return Tooltip(
      message: MaterialLocalizations.of(context).formatFullDate(time),
      child: child,
    );
  }

  @override
  List<Widget> buildWeekListWidget(
      BuildContext context, MaterialLocalizations localizations) {
    return localizations.narrowWeekdays
        .map(
          (d) => Expanded(
            child: ExcludeSemantics(
              child: Container(
                height: 60,
                alignment: Alignment.center,
                child: Text(
                  d,
                  style: TextStyle(
                      color: Colors.black,
                      fontSize: 18,
                      fontWeight: FontWeight.w600),
                ),
              ),
            ),
          ),
        )
        .toList();
  }

  @override
  double get childHeight => 50;

  @override
  FutureOr<bool> clickInterceptor(BuildContext context, DateTime dateTime) {
    return false;
  }

  @override
  bool isUnable(BuildContext context, DateTime time, bool isSameMonth) {
    return isSameMonth;
  }

  @override
  Widget buildTopWidget(BuildContext context, RCalendarController controller) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        IconButton(
          icon: Icon(Icons.chevron_left),
          onPressed: () {
            controller.previousPage();
          },
        ),
        SizedBox(
          width: 16,
        ),
        Text(
          DateFormat('yyyy-MM').format(controller.displayedMonthDate),
          style: TextStyle(color: Colors.red, fontSize: 18),
        ),
        SizedBox(
          width: 16,
        ),
        IconButton(
          icon: Icon(Icons.chevron_right),
          onPressed: () {
            controller.nextPage();
          },
        ),
      ],
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  r_calendar: ^0.1.7

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:r_calendar/r_calendar.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
58
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
79
Learn more about scoring.

We analyzed this package on Jun 5, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.2
  • pana: 0.13.8-dev
  • Flutter: 1.17.1

Health suggestions

Fix lib/src/r_calendar_controller.dart. (-0.50 points)

Analysis of lib/src/r_calendar_controller.dart reported 1 hint:

line 369 col 7: The declaration '_sortSelectDates' isn't referenced.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
intl ^0.16.0 0.16.1
Transitive dependencies
collection 1.14.12
meta 1.1.8
path 1.7.0
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test