0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flutter table_calendarとRiverpod カレンダーでタップした日を取得し色を付ける実装 

Posted at

はじめに

とりあえずできる画面はこんな感じです。

Riverpodの最初の設定部分は省いています

必要パッケージを入れる

まずは必要なパッケージを入れます。
riverpodはいくつか種類ありますがflutter_riverpodを選びます。
日本語化のためにintlも入れます。

flutter_riverpod
table_calendar
intl

pubspec.yaml
dev_dependencies:
  flutter_test:
    sdk: flutter

  # The "flutter_lints" package below contains a set of recommended lints to
  # encourage good coding practices. The lint set provided by the package is
  # activated in the `analysis_options.yaml` file located at the root of your
  # package. See that file for information about deactivating specific lint
  # rules and activating additional ones.
  flutter_lints: ^3.0.0
  flutter_riverpod: ^2.5.1
  table_calendar: ^3.1.2
  intl: ^0.19.0

まずはカレンダーを表示させる

lib/views/pages/home_page.dart
import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class HomePage extends ConsumerWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    return Scaffold(
      body: TableCalendar(
        firstDay: DateTime.utc(2010, 10, 16),
        lastDay: DateTime.utc(2030, 3, 14),
        focusedDay: DateTime.now(),
      ),
    );
  }
}

とりあえずこれだけでカレンダー自体は表示されます。簡単ですね!

Simulator Screenshot - iPhone SE (3rd generation) - 2024-09-03 at 22.47.58.png

firstDaylastDayfocusedDayが必須プロパティなので、それだけあれば一旦OKです。

Riverpodを使ってタップした日を選択する

さて、ここからが本題です。
実現したい動作は「選択した日付を取得しアクティブにする」です。

そのために、選択した日付をRiverpodで状態管理します。

Providerを作る

lib/models/calendar.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';

final selectedDateProvider = StateProvider<DateTime>((ref) => DateTime.now());

final focusedDateProvider = StateProvider<DateTime>((ref) => DateTime.now());

外部から変更可能なStateProviderを作ります。

カレンダーにはイベント関数OnDaySelectedがあり、それで2つのDateTime(selectedDayとfocusedDay)を受け取ります。

TableCalendarにonDaySelectedを追加

lib/views/pages/home_page.dart
class HomePage extends ConsumerWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final selectedDate = ref.watch(selectedDateProvider);
    final focusedDate = ref.watch(focusedDateProvider);

    return Scaffold(
      body: TableCalendar(
        firstDay: DateTime.utc(2010, 10, 16),
        lastDay: DateTime.utc(2030, 3, 14),
        focusedDay: focusedDate,
        currentDay: DateTime.now(),
        selectedDayPredicate: (day) {
          return isSameDay(selectedDate, day);
        },
        onDaySelected: (selectedDay, focusedDay) {
          print(selectedDay); // 選択した日がコンソールで表示
          ref.read(selectedDateProvider.notifier).state = selectedDay; // 選択した値に書き換え
          ref.read(focusedDateProvider.notifier).state = focusedDay; // 選択した値に書き換え
        },
      ),
    );
  }
}

これで日付を選択できるようになりました!:relieved:

カレンダーのデザインを変更

最後にカレンダーのデザインを少し変更します。
色を管理するThemeDataの作成と、カレンダーを日本語化します。

ThemeDataを作成

lib/theme.dart
import 'package:flutter/material.dart';

class AppTheme {
  static const Color lightGray = Color(0xFFF0F0F0);
  static const Color darkGray = Color(0xFFCCCCCC);

  static final ThemeData lightTheme = ThemeData(
    colorScheme: ColorScheme.fromSeed(
      brightness: Brightness.light,
      seedColor: const Color(0xFFF5BFC0),
      primary: const Color(0xFFF5BFC0),
    ),
    useMaterial3: true,
  );
}

main.dartでThemeDataを設定 & 日本語化

私はgo_routerを使ってるので少しデフォルト違いますが、大体こんな感じです。

lib/main.dart
import 'package:flutter/material.dart';
import 'package:h_calender/router.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:h_calender/theme.dart';
import 'package:intl/date_symbol_data_local.dart';

void main() {
  MyApp.run();
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'カレンダー',
      routerConfig: router,
      theme: AppTheme.lightTheme, // AppThemeクラスを使用
    );
  }

  static Future<void> run() async {
    await initializeDateFormatting('ja_JP').then((_) {
      WidgetsFlutterBinding.ensureInitialized();
      runApp(const ProviderScope(
        child: MyApp(),
      ));
    });
  }
}

最終的なカレンダーのコードはこちら!

lib/views/pages/home_page.dart
import 'package:flutter/material.dart';
import 'package:h_calender/models/calendar.dart';
import 'package:h_calender/theme.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class HomePage extends ConsumerWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final selectedDate = ref.watch(selectedDateProvider);
    final focusedDate = ref.watch(focusedDateProvider);
    final colorScheme = Theme.of(context).colorScheme;

    return Scaffold(
      body: TableCalendar(
        firstDay: DateTime.utc(2010, 10, 16),
        lastDay: DateTime.utc(2030, 3, 14),
        focusedDay: focusedDate,
        currentDay: DateTime.now(),
        selectedDayPredicate: (day) {
          return isSameDay(selectedDate, day);
        },
        locale: 'ja_JP',
        headerStyle: const HeaderStyle(
          formatButtonVisible: false,
          titleCentered: true,
        ),
        calendarStyle: CalendarStyle(
          todayDecoration: const BoxDecoration(
            color: AppTheme.darkGray, // 今日の日付の背景色
            shape: BoxShape.circle, // 形を丸く
          ),
          selectedDecoration: BoxDecoration(
              shape: BoxShape.circle, color: colorScheme.primary // 選択した日付の背景色
              ),
          todayTextStyle: const TextStyle(
            color: Colors.white, // 今日の日付の文字色
          ),
          selectedTextStyle: const TextStyle(
            color: Colors.white, // 選択した日付の文字色
          ),
        ),
        onDaySelected: (selectedDay, focusedDay) {
          ref.read(selectedDateProvider.notifier).state = selectedDay;
          ref.read(focusedDateProvider.notifier).state = focusedDay;
        },
      ),
    );
  }
}

カレンダーのデザイン部分は肥大化するので別クラスで切り分けると良さそうですね!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?