Open In App

Flutter – Create Interactive Event Calendars

Last Updated : 28 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

This article describes how to integrate event management functionality into a Flutter project. We will focus on adding and displaying events in a calendar interface. We will use the GetX package for routing and other utilities, but other solutions are also possible. We will use the get_cli tool to create a well-structured Flutter project. This tool helps us to generate complex project hierarchies, such as views, controllers, and pages.

The main focus of this article is on dynamically rendering events in the Flutter calendar. We will implement a demonstration program that displays events and allows users to create new events directly in the calendar interface. To do this, we will use the table_calendar package, which integrates seamlessly with Flutter and provides a comprehensive solution for managing events in a calendar environment.

Event Calander App

This is what we will be building in this article:

Use Case Or Why Integrate Event Calander In a Flutter App

There are many use cases for integrating an event calendar in a Flutter app. One of the most common is to allow users to view and manage their upcoming events, such as appointments, meetings, and social engagements. This can be helpful for users who need to stay organized and on top of their schedules. Another common use case is to display events that are relevant to the app’s content or purpose. For example, a news app could use an event calendar to display upcoming events in the local area, or a social media app could use an event calendar to display upcoming events that users are interested in.

Integrating an event calendar in a Flutter app can also be used to create new and innovative features. For example, a fitness app could use an event calendar to track users’ workouts and fitness goals. Or, a travel app could use an event calendar to display upcoming flights and hotel reservations.

What are the benefits of using the GetX package and the get_cli tool?

Benefits of using the GetX package:

  • Easy to learn and use: GetX is a relatively new state management library for Flutter, but it has quickly become popular due to its simplicity and ease of use. GetX provides a set of intuitive APIs that make it easy to manage state in your Flutter apps.
  • Powerful and flexible: GetX is a powerful and flexible state management library that can be used to build a wide variety of Flutter apps. GetX provides support for features such as dependency injection, reactive programming, and navigation management.
  • Lightweight and efficient: GetX is a lightweight and efficient state management library that has a minimal impact on the performance of your Flutter apps. GetX is also highly scalable, making it a good choice for both small and large-scale Flutter apps.

Benefits of using the get_cli tool:

  • Scaffolds new Flutter projects with GetX: get_cli can be used to scaffold new Flutter projects with GetX pre-integrated. This can save you a lot of time and effort, as you won’t need to manually configure GetX in your project.
  • Generates code for GetX components: get_cli can be used to generate code for GetX components, such as pages, controllers, and bindings. This can save you even more time and effort, as you won’t need to write this code yourself.
  • Provides a variety of other helpful commands: get_cli provides a variety of other helpful commands, such as commands for managing dependencies, running tests, and generating documentation. This can make your development workflow more efficient and productive.

What is the table_calendar package?

The table_calendar package is a Flutter package that provides a highly customizable, feature-packed calendar widget. It is easy to use and provides a preconfigured UI with customizable styling. It also supports custom selective builders for unlimited UI design, locale support, range selection support, multiple selection support, dynamic events and holidays, vertical autosizing, and multiple calendar formats (month, two weeks, week).

In simple words, the table_calendar package is a great way to add a calendar to your Flutter app. It is easy to use and provides a lot of features and customization options.

  • Here are some examples of how you can use the table_calendar package in your Flutter app:
  • Display a calendar of upcoming events, such as appointments, meetings, and social engagements.
  • Display a calendar of upcoming events that are relevant to your app’s content or purpose, such as upcoming news stories or upcoming social media events.
  • Use a calendar to track users’ progress towards a goal, such as a fitness goal or a learning goal.
  • Use a calendar to allow users to select dates and times for appointments or reservations.

Getting Started

Install get_cli globally:

To install get_cli globally we need to run this command from the root:

pub global activate get_cli

or

flutter pub global activate get_cli

If you are running one of these commands successfuly then you have get_cli installed on your system and now we can start using it.

Screenshot-from-2023-09-18-20-11-42

For more detailed instruction search get_cli on pub.dev.

Create Flutter Project

Create a flutter project, give it a name of your choice. And once done, open the root of the project in a terminal, and run the following command to start creating folder structure as per get_cli.

get init

Choose the default opetions like kotline, swift and else. Once you come to choose architecure you will choose Getx Cli and not clean architecutre.

Once done your project structure would look like this, but you won’t be having create_event and detail_screen directory as of now.

Screenshot-from-2023-09-18-20-29-30

Those will be created once you run the following command:

 get create page:create_event

and

get create page:detail_screen

Project Structure:

Below is the entire project structure you would have by now.


├── app
│ ├── data
│ ├── modules
│ │ └── home
│ │ ├── bindings
│ │ │ └── home_binding.dart
│ │ ├── controllers
│ │ │ └── home_controller.dart
│ │ ├── create_event
│ │ │ ├── bindings
│ │ │ │ └── create_event_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── create_event_controller.dart
│ │ │ └── views
│ │ │ └── create_event_view.dart
│ │ ├── detail_screen
│ │ │ ├── bindings
│ │ │ │ └── detail_screen_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── detail_screen_controller.dart
│ │ │ └── views
│ │ │ └── detail_screen_view.dart
│ │ └── views
│ │ └── home_view.dart
│ └── routes
│ ├── app_pages.dart
│ └── app_routes.dart
├── main.dart
└── static
└── utils.dart


Now we are going to start the actual coding part.

main.dart

Dart




import 'package:flutter/material.dart';
  
import 'package:get/get.dart';
  
import 'app/routes/app_pages.dart';
  
void main() {
  runApp(
    GetMaterialApp(
      title: "Application",
      initialRoute: AppPages.INITIAL,
      getPages: AppPages.routes,
      theme: ThemeData(
          // Darrk theme
          brightness: Brightness.dark,
          primarySwatch: Colors.grey),
    ),
  );
}


In this main.dart code above, a Flutter application is being initialized using the runApp method. The application is built using the GetX library, as indicated by the GetMaterialApp widget. Key attributes are set, such as the app’s title, initial route, navigation routes, and theme configuration. Notably, the theme is defined as a dark theme with a grey primary swatch. This code serves as the entry point for the Flutter application, defining its structure and initial configuration for navigation and theming.

Now lets see how we have initialied the routes in this app.

app_pages.dart

Dart




import 'package:get/get.dart';
  
import '../modules/home/create_event/bindings/create_event_binding.dart';
import '../modules/home/create_event/views/create_event_view.dart';
import '../modules/home/detail_screen/bindings/detail_screen_binding.dart';
import '../modules/home/detail_screen/views/detail_screen_view.dart';
import '../modules/home/bindings/home_binding.dart';
import '../modules/home/views/home_view.dart';
  
part 'app_routes.dart';
  
// class AppPages 
class AppPages {
  AppPages._();
  
  static const INITIAL = Routes.HOME;
  
  static final routes = [
    // getPages to create a list of GetPage to be 
    // used in the GetMaterialApp.router property.
    GetPage(
      name: _Paths.HOME,
      page: () => const CustomTableCalendar(),
      binding: HomeBinding(),
    ),
    GetPage(
      name: _Paths.CREATE_EVENT,
      page: () => SecondScreen(),
      binding: CreateEventBinding(),
    ),
  ];
}


In this file we have defined routing configurations for a Flutter application using the GetX library. It starts by importing necessary modules and widgets. The code also imports specific bindings and views for different screens, like the home screen, create event screen, and detail screen, ensuring that data dependencies are resolved correctly when these screens are accessed.

The AppPages class centralizes routing information, specifying the initial route as the home screen. The routes list contains definitions for various routes, associating each route name with a corresponding view and binding. For instance, the ‘HOME‘ route is linked to the CustomTableCalendar view and the HomeBinding binding, while the ‘CREATE_EVENT‘ route corresponds to the SecondScreen view and the CreateEventBinding binding. This code helps manage navigation and data binding within the Flutter application efficiently.

home_binding.dart

Dart




import 'package:get/get.dart';
  
import '../controllers/home_controller.dart';
  
// this class is used to inject dependencies in your controller
class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<HomeController>(
      () => HomeController(),
    );
  }
}


This Dart code, used in a Flutter app with GetX, manages and injects dependencies into the HomeController class. It extends the Bindings class, indicating that an instance of HomeController is lazily created and associated with GetX, ensuring efficient dependency management in the app. This enhances organization and efficiency in handling dependencies within the Flutter application.

One good thing about git_cli is that we don’t need to worry about the creation of these above boiler plate code for routing and binding.

Before getting on to the home page, let’s first make a class which will contain the colors used in our app.

Dart




import 'package:flutter/material.dart';
  
// The AppColors class stores color constants used throughout the application.
class AppColors {
  AppColors._(); // Private constructor to prevent instantiation.
  
  // Define color constants as static members of the class.
  static const Color blackCoffee = Color(0xFF352d39); // Dark brownish-black color.
  static const Color eggPlant = Color(0xFF6d435a); // Eggplant purple color.
  static const Color celeste = Color(0xFFb1ede8); // Light blue-green color.
  static const Color babyPowder = Color(0xFFFFFcF9); // Soft off-white color.
  static const Color ultraRed = Color(0xFFFF6978); // Bright red color.
}


In this code, the AppColors class serves as a convenient way to access and reuse color values throughout your Flutter application. These color constants are defined as static const members of the class, making it easy to reference them in different parts of your code to ensure consistent and maintainable color theming.

Now we will start coding the home page of our app.

home_view.dart

Dart




// Scaffold widget is used to create the app's basic structure.
Scaffold(
  appBar: AppBar(
    title: const Text('Schedule'), // Set the app's title.
    // Add a hamburger menu icon to the leading position in the app bar.
    leading: Builder(
      builder: (context) => IconButton(
        icon: const Icon(Icons.menu),
        onPressed: () => Scaffold.of(context).openDrawer(),
      ),
    ),
    // Add a notification icon with a red circle in the app bar's actions.
    actions: [
      Stack(
        children: [
          IconButton(
            onPressed: () {},
            icon: const Icon(Icons.notifications),
          ),
          Positioned(
            right: 11,
            top: 11,
            child: Container(
              padding: const EdgeInsets.all(1),
              decoration: BoxDecoration(
                color: AppColors.ultraRed, // Red circle color.
                borderRadius: BorderRadius.circular(6),
              ),
              constraints: const BoxConstraints(
                minWidth: 14,
                minHeight: 14,
              ),
              child: const Text(
                '3', // Display the notification count.
                style: TextStyle(
                  color: AppColors.babyPowder, // Text color.
                  fontSize: 8,
                ),
                textAlign: TextAlign.center,
              ),
            ),
          )
        ],
      ),
    ],
  ),
  // Drawer widget creates a side navigation menu.
  drawer: Drawer(
    child: ListView(
      padding: EdgeInsets.zero,
      children: [
        const DrawerHeader(
          decoration: BoxDecoration(
            color: AppColors.eggPlant, // Header background color.
          ),
          child: Text(
            'Menu',
            style: TextStyle(
              color: AppColors.babyPowder, // Header text color.
              fontSize: 24,
            ),
          ),
        ),
        ListTile(
          leading: const Icon(Icons.home),
          title: const Text('Home'),
          onTap: () {
            Navigator.pop(context); // Close the drawer when Home is tapped.
          },
        ),
        ListTile(
          leading: const Icon(Icons.calendar_today),
          title: const Text('Calendar'),
          onTap: () {
            Navigator.pop(context); // Close the drawer when Calendar is tapped.
          },
        ),
        ListTile(
          leading: const Icon(Icons.settings),
          title: const Text('Settings'),
          onTap: () {
            Navigator.pop(context); // Close the drawer when Settings is tapped.
          },
        ),
      ],
    ),
  ),
  // Floating action button with an edit icon.
  floatingActionButton: FloatingActionButton(
    onPressed: () => _navigateToAddEventScreen(), // Define the onPressed action.
    child: Icon(
      Icons.edit,
      color: Colors.black,
    ),
    backgroundColor: AppColors.babyPowder, // Background color of the button.
  ),
  body: SingleChildScrollView(
    child: Column(
      children: [
        // Card widget for displaying content with a card-like design.
        Card(
          margin: const EdgeInsets.all(8.0),
          elevation: 5.0,
          shape: const RoundedRectangleBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(10),
            ),
            side: BorderSide(
                color: AppColors.blackCoffee, width: 2.0), // Card border.
          ),
          child: TableCalendar(
            calendarFormat: _calendarFormat, // Define the calendar format.
  
            focusedDay: _focusedCalendarDate, // Set the focused calendar day.
            // today's date
            firstDay: _initialCalendarDate, // Set the earliest possible date.
            lastDay: _lastCalendarDate, // Set the latest allowed date.
              
            // ... (Additional calendar settings and styles)
              
            // Event loader function to load events for specific dates.
  
            // ... (Header style and other calendar styles)
              
            selectedDayPredicate: (currentSelectedDate) {
              // Predicate to determine the currently selected day.
              return (isSameDay(selectedCalendarDate!, currentSelectedDate));
            },
            onDaySelected: (selectedDay, focusedDay) {
              // Action when a day is selected.
              if (!isSameDay(selectedCalendarDate, selectedDay)) {
                setState(() {
                  selectedCalendarDate = selectedDay;
                  _focusedCalendarDate = focusedDay;
                });
              }
            },
          ),
        ),
        // Map over a list of events and display them as ListTiles.
  
        // ... (List item styling and onTap actions)
         ..._listOfDayEvents(selectedCalendarDate!).map(
              (myEvents) => GestureDetector(
                onTap: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => DetailScreen(
                        eventTitle: myEvents.eventTitle,
                        eventDescp: myEvents.eventDescp,
                        eventDate: selectedCalendarDate!,
                      ),
                    ),
                  );
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                      horizontal: 12.0, vertical: 8.0),
                  child: ListTile(
                    // add rounded border to list item
                    shape: RoundedRectangleBorder(
                      side: BorderSide(color: AppColors.eggPlant, width: 2.0),
                      borderRadius: BorderRadius.circular(10.0),
                    ),
  
                    leading: Container(
                      width: 50,
                      height: 50,
                      decoration: BoxDecoration(
                        color: AppColors.eggPlant,
                        shape: BoxShape.circle,
                      ),
                      child: const Icon(
                        Icons.done,
                        color: AppColors.babyPowder,
                      ),
                    ),
                    // in trailing add forward icon
                    trailing: const Icon(
                      Icons.arrow_forward_ios,
                      color: AppColors.eggPlant,
                    ),
  
                    title: Padding(
                      padding: const EdgeInsets.only(bottom: 8.0),
                      child: Text(
                        '${myEvents.eventTitle}',
                        style: TextStyle(
                            fontSize: 20, fontWeight: FontWeight.bold),
                      ),
                    ),
                    subtitle: Text('${myEvents.eventDescp}'),
                  ),
                ),
              ),
            ),
      ],
    ),
  ),
);


Here we will try to explain the flow of code from top to bottom:

AppBar Configuration:

  • The Scaffold widget is used to create the app’s basic structure.
  • Inside the Scaffold, the appBar property configures the top app bar.
  • It sets the title of the app bar to ‘Schedule’ using const Text(‘Schedule’).
  • The leading property adds a hamburger menu icon to the left of the app bar. When pressed, it opens the drawer. This is achieved using an IconButton with an onPressed function that calls Scaffold.of(context).openDrawer().

Drawer Configuration:

  • Below the appBar, the drawer property configures the side navigation menu.
  • Inside the Drawer, a ListView widget is used to list menu items.
  • The DrawerHeader provides a header with the text ‘Menu’ and a specific background color (AppColors.eggPlant).
  • ListTile widgets represent individual menu items, such as ‘Home’, ‘Calendar’, and ‘Settings’.
  • Each ListTile has an onTap function to handle tap events, and Navigator.pop(context) is used to close the drawer when an item is tapped.

Floating Action Button Configuration:

  • The floatingActionButton property configures a floating action button (FAB).
  • The FAB has an onPressed function that calls _navigateToAddEventScreen().
  • The FAB’s child is an icon (Icons.edit) with black color.
  • The background color of the FAB is set to AppColors.babyPowder.
  • The floatingActionButton property configures a floating action button (FAB).
  • The FAB has an onPressed function that calls _navigateToAddEventScreen().
  • The FAB’s child is an icon (Icons.edit) with black color.
  • The background color of the FAB is set to AppColors.babyPowder.

Body Configuration:

  • The body property defines the main content of the Scaffold.
  • It uses a SingleChildScrollView widget to allow scrolling if the content exceeds the screen height.
  • Inside the SingleChildScrollView, a Column widget is used to arrange multiple widgets vertically.
  • A Card widget is used to display content with a card-like design. It includes a TableCalendar widget for displaying a calendar.
  • Additional calendar settings and styles are configured within the TableCalendar.

List of Events:

  • Below the Card, there’s a section for displaying a list of events.
  • A map function is used to iterate over a list of events and display them as GestureDetector widgets.
  • Each event item is displayed as a ListTile with specific styling.
  • Tapping an event item navigates to a DetailScreen with details of the selected event.

The above code represents the structure and layout of a Flutter app screen, including an app bar, navigation drawer, calendar, and a list of events. Below we will write the function that will add on to the functionality of the app.

Dart




// This function is used to navigate to the 'SecondScreen' and handle the result.
void _navigateToAddEventScreen() async {
  // Use Navigator.push to navigate to 'SecondScreen'.
  final result = await Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => SecondScreen()), // Create the route.
  );
  
  // Check if a result is returned and if it is of type 'MyEvents'.
  if (result != null && result is MyEvents) {
    // Retrieve the list of events for
    // the selected calendar date 
    // or initialize an empty list.
    final selectedDateEvents = mySelectedEvents[selectedCalendarDate] ?? [];
  
    // Update the list of events with 
    // the result from 'SecondScreen'.
    setState(() {
      // Add the new event to the list
      selectedDateEvents.add(result); 
        
      // Update the events for the selected date
      mySelectedEvents[selectedCalendarDate!] = selectedDateEvents; 
    });
  }
}


This code defines a function _navigateToAddEventScreen that handles navigation to the ‘SecondScreen’ and manages the result returned from that screen. It checks if a result is received and if it’s of type ‘MyEvents’. If so, it updates the list of events for the selected calendar date.

Dart




// This function displays an AlertDialog to add a new event.
_showAddEventDialog() async {
  // Show the dialog with title and content.
  await showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('New Event'), // Dialog title.
      content: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        mainAxisSize: MainAxisSize.min,
        children: [
          // Create a text field for entering the event title.
          buildTextField(
            controller: titleController, 
            hint: 'Enter Title'
          ),
          const SizedBox(
            height: 20.0,
          ),
          // Create a text field for entering the event description.
          buildTextField(
            controller: descpController, 
            hint: 'Enter Description'
          ),
        ],
      ),
      actions: [
        // Cancel button to close the dialog.
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('Cancel'),
        ),
        // Add button to add the event.
        TextButton(
          onPressed: () {
            // Check if both title and description fields are empty.
            if (titleController.text.isEmpty && descpController.text.isEmpty) {
              // Show a snackbar with a message.
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(
                  content: Text('Please enter title & description'),
                  duration: Duration(seconds: 3),
                ),
              );
              return; // Exit the function.
            } else {
              setState(() {
                // Check if events for the selected date exist.
                if (mySelectedEvents[selectedCalendarDate] != null) {
                  // Add the new event to the existing events list.
                  mySelectedEvents[selectedCalendarDate]?.add(MyEvents(
                    eventTitle: titleController.text,
                    eventDescp: descpController.text,
                  ));
                } else {
                  // Create a new events list for the selected date.
                  mySelectedEvents[selectedCalendarDate!] = [
                    MyEvents(
                      eventTitle: titleController.text,
                      eventDescp: descpController.text,
                    ),
                  ];
                }
                print('Added event on date: $selectedCalendarDate');
              });
  
              titleController.clear(); // Clear the title field.
              descpController.clear(); // Clear the description field.
  
              Navigator.pop(context); // Close the dialog.
              return; // Exit the function.
            }
          },
          child: const Text('Add'), // Text for the Add button.
        ),
      ],
    ),
  );
}


This function creates an AlertDialog for adding a new event, including fields for entering the event title and description. It also handles validation and adds the event to the appropriate list when the “Add” button is pressed.

Dart




// This function creates and returns a TextField widget with specified properties.
Widget buildTextField({String? hint, required TextEditingController controller}) {
  // Create a TextField widget with the provided controller.
  return TextField(
    controller: controller,
    textCapitalization: TextCapitalization.words, // Capitalize each word in the input.
    decoration: InputDecoration(
      labelText: hint ?? '', // Set the label text to the provided hint, or empty if not provided.
      focusedBorder: OutlineInputBorder(
        // Define the border when the TextField is focused.
        borderSide: const BorderSide(color: AppColors.eggPlant, width: 1.5), // Border color and width.
        borderRadius: BorderRadius.circular(10.0), // Border radius.
      ),
      enabledBorder: OutlineInputBorder(
        // Define the border when the TextField is not focused.
        borderSide: const BorderSide(color: AppColors.eggPlant, width: 1.5), // Border color and width.
        borderRadius: BorderRadius.circular(10.0), // Border radius.
      ),
    ),
  );
}


This function creates a reusable TextField widget with specific properties. It can be used to build text input fields throughout the application. The function allows you to customize the hint text, controller, and text capitalization while providing consistent border styling for focused and non-focused states.

Screenshot-from-2023-09-18-23-40-58

This concludes our apps home page. Now we will work on the screen from where we can add events.

create_event_view.dart

Import Statements:

Dart




import 'package:assignment_one/app/modules/home/views/home_view.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/create_event_controller.dart';


In this section, you import necessary packages and modules required for this Dart file. This includes Flutter’s material.dart for UI components and get.dart for state management. You also import home_view.dart and a custom controller (create_event_controller.dart) that appear to be used elsewhere in the code.

SecondScreen Class Definition:

Dart




class SecondScreen extends StatefulWidget {
  @override
  _SecondScreenState createState() => _SecondScreenState();
}


Here, you define a SecondScreen class that extends StatefulWidget. This class represents the screen where users can add events.

_SecondScreenState Class Definition:

Dart




class _SecondScreenState extends State<SecondScreen> {
  // Create TextEditingController instances for handling input fields.
  final TextEditingController titleController = TextEditingController();
  final TextEditingController descpController = TextEditingController();


This section defines the _SecondScreenState class, which extends State<_SecondScreenState>. In this class, you create two TextEditingController instances named titleController and descpController. These controllers are used to manage the text input fields for event title and description.

dispose() Method:

Dart




@override
void dispose() {
  // Dispose of the TextEditingController instances to free resources.
  titleController.dispose();
  descpController.dispose();
  super.dispose();
}


The dispose() method is an overridden method that gets called when the state object is no longer needed. In this case, it disposes of the text controllers to release resources and prevent memory leaks.

Widget build(BuildContext context) Method:

Dart




@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Add Event'), // Set the app bar title.
    ),


This is the core of your widget, the build method. It returns a Scaffold widget, which provides the basic structure for your screen. The AppBar widget is used to display a navigation bar with the title “Add Event.”

Body of the Screen:

Dart




body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Text(
              'Add Event',
              style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
       ),


Inside the Scaffold, you have the screen’s body. This includes a Padding widget to provide space around the content. Within the padding, you have a Column widget, which arranges its children vertically.

Text Widget – “Add Event” Title:

Dart




Text(
    'Add Event',
     style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
),


Here, you display the text “Add Event” as a title for this screen. You set the text style with a larger font size and bold weight.

Text Input Fields:

Dart




// Create and display a text input field for entering the event title.
buildTextField(controller: titleController, hint: 'Enter Title'),
SizedBox(height: 20.0),
// Create and display a text input field for entering the event description.
buildTextField(controller: descpController, hint: 'Enter Description'),


These lines create and display two text input fields for entering the event title and description. The buildTextField function is called to create these input fields. The titleController and descpController are provided as controllers for managing the text input.

Add Event Button:

Dart




ElevatedButton(
              onPressed: () {
                // Check if either title or description is empty.
                if (titleController.text.isEmpty || descpController.text.isEmpty) {
                  // Show a snackbar with a message if fields are empty.
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                      content: Text('Please enter title and description'),
                      duration: Duration(seconds: 3),
                    ),
                  );
                } else {
                  // Create an event object with the entered title and description.
                  final event = MyEvents(
                    eventTitle: titleController.text,
                    eventDescp: descpController.text,
                  );
  
                  // Pop the current screen and pass the event object as the result.
                  Navigator.pop(context, event);
                }
              },
              child: Text('Add Event'), // Text for the button.
            ),
          ],
        ),
      ),
   );
}


In this section, you create an “Add Event” button as an ElevatedButton. When pressed, it checks if either the title or description fields are empty. If they are empty, it shows a snackbar with an error message. Otherwise, it creates an event object with the entered title and description, and then it pops (closes) the current screen and passes the event object back to the previous screen as the result.

buildTextField() Function:

Dart




// Widget function to create and return a text input field.
Widget buildTextField(
    {required TextEditingController controller, String? hint}) {
  return TextField(
    controller: controller,
    decoration: InputDecoration(
      labelText: hint ?? '', // Set the label text to the provided hint or empty.
      border: OutlineInputBorder(), // Define input field border.
    ),
  );
}


This is a separate function, buildTextField(), used to create and return a text input field. It takes a TextEditingController and an optional hint as parameters and returns a TextField widget with the provided controller and decoration.

Screenshot-from-2023-09-18-23-57-19

How we can add events on the from this screen which will get reflected on the home of the app.

Screenshot-from-2023-09-18-23-58-52

Now, lets quickly code the deail screen, which will show the detail of the events which are tapped.

detail_screen_view.dart

Import Statements:

Dart




import 'package:intl/intl.dart';
import '../controllers/detail_screen_controller.dart';


  • This section includes import statements to bring in external libraries and controllers needed for this Dart file.
  • intl is imported from the intl package, which is used for date formatting.
  • detail_screen_controller.dart is imported, which likely contains additional logic for this screen.

Class Definition:

Dart




class DetailScreen extends StatelessWidget {
  final String eventTitle;
  final String eventDescp;
  final DateTime eventDate;
    
  DetailScreen({
    required this.eventTitle,
    required this.eventDescp,
    required this.eventDate,
  });


  • This defines a class named DetailScreen, which extends StatelessWidget. It’s used to create the detail view of an event.
  • It has three properties: eventTitle, eventDescp, and eventDate, which are required when creating an instance of this class. These properties hold information about the event to be displayed.

Build Method:

Dart




@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Event Details'),
    ),
    body: Column(
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        // ... Widget tree for displaying event details
      ],
    ),
  );
}


  • This is the build method, required for all widgets in Flutter. It defines the layout and structure of the screen.
  • The Scaffold widget is used to create the overall screen structure with an app bar and body.
  • Inside the body, there’s a Column widget, which arranges its children vertically.

Event Image:

Dart




Padding(
  padding: const EdgeInsets.only(top: 12, bottom: 5, right: 12, left: 12),
  child: Container(
    height: 200.0,
    width: double.infinity,
    decoration: const BoxDecoration(
      color: AppColors.eggPlant,
      borderRadius: BorderRadius.only(
        topLeft: Radius.circular(10),
        topRight: Radius.circular(10),
        bottomLeft: Radius.circular(10),
        bottomRight: Radius.circular(10),
      ),
      image: DecorationImage(
        image: AssetImage('assets/event.jpg'),
        fit: BoxFit.cover,
      ),
    ),
  ),
),


  • This part creates a container displaying an event image.
  • It uses the Padding widget to add spacing around the container.
  • The Container has a fixed height and width, and it’s decorated with a purple background color and rounded corners.
  • The event image is set as the background using DecorationImage.

Event Details:

Dart




Container(
  decoration: BoxDecoration(
    color: const Color.fromARGB(255, 53, 53, 53),
    borderRadius: BorderRadius.circular(10),
  ),
  padding: EdgeInsets.all(20),
  margin: EdgeInsets.symmetric(horizontal: 12, vertical: 5),
  child: Column(
    children: [
      // ... Widget tree for displaying event details
    ],
  ),
),


  • This section creates a container for displaying event details with a dark grey background.
  • It has padding and margin to control spacing.
  • Inside the container, there’s a Column widget to arrange details vertically.

Event Title:

Dart




RichText(
  text: TextSpan(
    text: 'Event: ',
    style: TextStyle(
      fontSize: 22,
      fontWeight: FontWeight.bold,
      color: AppColors.eggPlant,
    ),
    children: <TextSpan>[
      TextSpan(
        text: '$eventTitle',
        style: TextStyle(
          fontSize: 22,
          fontWeight: FontWeight.bold,
          color: Colors.white,
        ),
      ),
    ],
  ),
),


  • This part uses RichText to display the event title with custom styling.
  • It combines “Event: ” in purple and the actual event title in white.

Location and Date:

Dart




Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    Row(
      children: [
        Icon(
          Icons.location_on,
          color: AppColors.eggPlant,
        ),
        Text('  Johansi Berline'),
      ],
    ),
    Row(
      children: [
        Icon(
          Icons.access_time,
          color: AppColors.eggPlant,
        ),
        Text('  ${DateFormat('yyyy-MM-dd').format(eventDate)}'),
      ],
    ),
  ],
),


  • This section displays the event location and date.
  • It uses two Row widgets to create two separate rows, one for location and one for the date.
  • Icons are used for location and time, and they are styled with a purple color.

Event Description:

Dart




SizedBox(
  child: Row(
    children: [
      SizedBox(
        width: 320,
        child: Text(
          'Description: $eventDescp',
          style: TextStyle(fontSize: 18, color: Colors.grey),
        ),
      ),
    ],
  ),
),


  • This part displays the event description.
  • It uses a Text widget with custom styling, including a grey color for the description text.

Action Button:

Dart




Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    OutlinedButton(
      // Cancel button styling
      onPressed: () {},
      child: Text(
        'Cancel',
        style: TextStyle(color: Colors.grey, fontSize: 20),
      ),
    ),
    OutlinedButton(
      // Join button styling
      onPressed: () {},
      child: Text(
        'Join',
        style: TextStyle(color: AppColors.eggPlant, fontSize: 20),
      ),
    ),
  ],
),


This section creates two action buttons: “Cancel” and “Join.”

  • The buttons use OutlinedButton with custom styling for appearance.
  • Both buttons have onPressed handlers, but they are currently empty and need to be implemented for functionality.

Screenshot-from-2023-09-19-00-03-27

This marks the completeness of the event detail screen. So this concluded the flutter event table calander.

Output:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads