Search code examples
flutterdartcalendarappbar

How do construct a horizontally scrollable calendar in my appbar with Flutter?


enter image description herethis is how it is looking right now

this is how it is looking right now for me.

expected design of the calendar

I haven't been able to find any plugins or any way to build this specific type of widget. I have been having trouble with this so your help will be immensely appreciated.

import 'package:flutter/material.dart';
import 'package:healthonify_mobile/constants/text_styles.dart';
import 'package:healthonify_mobile/widgets/cards/add_workout.dart';
import 'package:healthonify_mobile/widgets/cards/average_calories_burnt.dart';
import 'package:healthonify_mobile/widgets/cards/reminder_card.dart';
import 'package:healthonify_mobile/widgets/cards/steps_card.dart';
import 'package:healthonify_mobile/widgets/cards/track_workout.dart';
import 'package:healthonify_mobile/widgets/cards/workout_details.dart';
import 'package:healthonify_mobile/widgets/other/calendar_appbar.dart';

class WorkoutScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: CalendarAppBar(),
        body: SingleChildScrollView(
          physics: BouncingScrollPhysics(),
          child: Column(
            children: [
              SizedBox(height: 12),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  WorkoutDetailsCard(),
                ],
              ),
              SizedBox(height: 22),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  StepsCard(),
                ],
              ),
              SizedBox(height: 22),
              Row(
                children: [
                  Padding(
                    padding: const EdgeInsets.only(left: 16),
                    child: Text(
                      'Track your workout',
                      style: openSans22DarkBold,
                    ),
                  ),
                ],
              ),
              SizedBox(height: 12),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  TrackWorkoutCard(),
                ],
              ),
              SizedBox(height: 22),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  AddWorkoutCard(),
                ],
              ),
              SizedBox(height: 22),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  AverageCalBurntCard(),
                ],
              ),
              SizedBox(height: 22),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ReminderCard(),
                ],
              ),
              SizedBox(height: 34),
            ],
          ),
        ),
      ),
    );
  }
}


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

class CalendarAppBar extends StatefulWidget implements PreferredSizeWidget {
  const CalendarAppBar({Key? key}) : super(key: key);

  @override
  Size get preferredSize => const Size.fromHeight(148.0);

  @override
  State<CalendarAppBar> createState() => _CalendarAppBarState();
}

class _CalendarAppBarState extends State<CalendarAppBar> {
  int selectedIndex = 0;
  DateTime now = DateTime.now();
  late DateTime lastDayOfMonth;
  @override
  void initState() {
    super.initState();
    lastDayOfMonth = DateTime(now.year, now.month + 1, 0);
  }

  @override
  Widget build(BuildContext context) {
    return AppBar(
      backgroundColor: Colors.white,
      toolbarHeight: 148.0,
      title: Column(
        children: [
          Row(
            children: const [
              Icon(
                Icons.arrow_back_ios,
                color: Colors.orange,
              ),
              Expanded(
                child: Text(
                  "Workout",
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Colors.black,
                  ),
                ),
              ),
            ],
          ),
          const SizedBox(height: 16.0),
          SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            physics: const ClampingScrollPhysics(),
            child: Row(
              children: List.generate(
                lastDayOfMonth.day,
                (index) {
                  final currentDate =
                      lastDayOfMonth.add(Duration(days: index + 1));
                  final dayName = DateFormat('E').format(currentDate);
                  return Padding(
                    padding: EdgeInsets.only(
                        left: index == 0 ? 16.0 : 0.0, right: 16.0),
                    child: GestureDetector(
                      onTap: () => setState(
                        () {
                          selectedIndex = index;
                        },
                      ),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Container(
                            height: 42.0,
                            width: 42.0,
                            alignment: Alignment.center,
                            decoration: BoxDecoration(
                              color: selectedIndex == index
                                  ? Colors.orange
                                  : Colors.transparent,
                              borderRadius: BorderRadius.circular(44.0),
                            ),
                            child: Text(
                              dayName.substring(0, 1),
                              style: TextStyle(
                                fontSize: 24.0,
                                color: selectedIndex == index
                                    ? Colors.white
                                    : Colors.black54,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                          ),
                          const SizedBox(height: 8.0),
                          Text(
                            "${index + 1}",
                            style: const TextStyle(
                              fontSize: 16.0,
                              color: Colors.black54,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                          const SizedBox(height: 8.0),
                          Container(
                            height: 2.0,
                            width: 28.0,
                            color: selectedIndex == index
                                ? Colors.orange
                                : Colors.transparent,
                          ),
                        ],
                      ),
                    ),
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Here is some of the code that is using the appbar and there is not more than this linking elsewhere in the app so basically it is just 2 screens. i dont understand why the appbar is aligning the the left automatically even though i have no padding or offset.


Solution

  • try below code you get exact output based on your description

    add package in pubspec.yaml file

    intl: ^0.17.0
    

    Output:-

    enter image description here

    Code:-

    import 'package:intl/intl.dart';
    import 'package:flutter/material.dart';
    
    class DatePickerCustom extends StatefulWidget {
      const DatePickerCustom({Key? key}) : super(key: key);
    
      @override
      State<DatePickerCustom> createState() => _DatePickerCustomState();
    }
    
    class _DatePickerCustomState extends State<DatePickerCustom> {
      int selectedIndex = 0;
      DateTime now = DateTime.now();
      late DateTime lastDayOfMonth;
      @override
      void initState() {
        super.initState();
        lastDayOfMonth = DateTime(now.year, now.month + 1, 0);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.white,
          appBar: AppBar(
            backgroundColor: Colors.white,
            toolbarHeight: 148.0,
            title: Column(
              children: [
                Row(
                  children: const [
                    Icon(
                      Icons.arrow_back_ios,
                      color: Colors.orange,
                    ),
                    Expanded(
                        child: Text("Workout",
                            textAlign: TextAlign.center,
                            style: TextStyle(
                              color: Colors.black,
                            )))
                  ],
                ),
                const SizedBox(height: 16.0),
                SingleChildScrollView(
                  scrollDirection: Axis.horizontal,
                  physics: const ClampingScrollPhysics(),
                  child: Row(
                    children: List.generate(
                      lastDayOfMonth.day,
                      (index) {
                        final currentDate =
                            lastDayOfMonth.add(Duration(days: index + 1));
                        final dayName = DateFormat('E').format(currentDate);
                        return Padding(
                          padding: EdgeInsets.only(
                              left: index == 0 ? 16.0 : 0.0, right: 16.0),
                          child: GestureDetector(
                            onTap: () => setState(() {
                              selectedIndex = index;
                            }),
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                Container(
                                  height: 42.0,
                                  width: 42.0,
                                  alignment: Alignment.center,
                                  decoration: BoxDecoration(
                                    color: selectedIndex == index
                                        ? Colors.orange
                                        : Colors.transparent,
                                    borderRadius: BorderRadius.circular(44.0),
                                  ),
                                  child: Text(
                                    dayName.substring(0, 1),
                                    style: TextStyle(
                                      fontSize: 24.0,
                                      color: selectedIndex == index
                                          ? Colors.white
                                          : Colors.black54,
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                ),
                                const SizedBox(height: 8.0),
                                Text(
                                  "${index + 1}",
                                  style: const TextStyle(
                                    fontSize: 16.0,
                                    color: Colors.black54,
                                    fontWeight: FontWeight.bold,
                                  ),
                                ),
                                const SizedBox(height: 8.0),
                                Container(
                                  height: 2.0,
                                  width: 28.0,
                                  color: selectedIndex == index
                                      ? Colors.orange
                                      : Colors.transparent,
                                ),
                              ],
                            ),
                          ),
                        );
                      },
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }