如何在 flutter 中更改此日历小部件中的选定日期?

How can I change the selected date in this calendar widget in flutter?

我正在尝试制作一个可以选择一个日期的日历小部件,我可以使用硬编码设置所选日期,但我希望能够从内部小部件 (DayWidget) 更改所选日期。

我的代码:

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

class HorizontalCalendar extends StatefulWidget {
  final double height;
  final double width;
  final EdgeInsets padding;
  final EdgeInsets margin;
  final int month;
  final int year;
  final int selectedDate;
  HorizontalCalendar({
    @required this.year,
    @required this.month,
    this.selectedDate,
    this.height,
    this.width,
    this.margin = const EdgeInsets.all(0),
    this.padding = const EdgeInsets.all(0),
  });
  @override
  _HorizontalCalendarState createState() => _HorizontalCalendarState();
}

class _HorizontalCalendarState extends State<HorizontalCalendar> {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: widget.height,
      margin: widget.margin,
      padding: widget.padding,
      child: ListView.builder(
        scrollDirection: Axis.horizontal,
        itemCount: DateTime(widget.year, widget.month + 1, 0).day,
        itemBuilder: (context, index) {
          index = index + 1;
          DateTime date = DateTime(widget.year, widget.month, index);
          return DayWidget(
            day: index,
            dayName: DateFormat('EEEE').format(date).substring(0, 3),
            selected: widget.selectedDate == index ? true : false,
          );
        },
      ),
    );
  }
}

日小部件:

class DayWidget extends StatelessWidget {
  final int day;
  final String dayName;
  final bool selected;
  DayWidget({this.day, this.dayName, this.selected = false});
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(horizontal: 5),
      child: SizedBox(
        width: MediaQuery.of(context).size.width * 0.17,
        child: FlatButton(
          color: selected ? Colors.white : Colors.transparent,
          shape: new RoundedRectangleBorder(
              borderRadius: new BorderRadius.circular(15.0),
              side: BorderSide(
                  color: selected ? Colors.white : Colors.grey,
                  width: 1,
                  style: BorderStyle.solid)),
          onPressed: () {
            // Here I should be able to change the selected date from
            // The HorizontalCalendar
          },
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              Text(
                dayName,
                style: TextStyle(
                    color: selected ? Colors.blueGrey : Colors.white60,
                    fontSize: 15,
                    fontWeight: selected ? FontWeight.w900 : FontWeight.w300),
              ),
              Text(
                day.toString(),
                style: TextStyle(
                    color: selected ? Colors.blueGrey : Colors.white,
                    fontSize: 24,
                    fontWeight: selected ? FontWeight.w900 : FontWeight.w500),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

image of the widget for clarification

我试图在按下 DayWidget 时更改选定的日期,但我似乎无法访问 Horizo​​ntalCalendar 小部件,我试图将方法设置为静态,但如果我在 Horizo​​ntalCalendar 静态中设置方法,我无法使用 setState 更新视图。

请指导我更好地实现它。

  1. 首先我们需要移动 selectedDate 到可变变量。我们需要在 _HorizontalCalendarState class.
  2. 上重新声明它
class HorizontalCalendar extends StatefulWidget {
  final double height;
  final double width;
  final EdgeInsets padding;
  final EdgeInsets margin;
  final int month;
  final int year;
  final int selectedDate; // this is immutable
  HorizontalCalendar({
    @required this.year,
    @required this.month,
    this.selectedDate,
    this.height,
    this.width,
    this.margin = const EdgeInsets.all(0),
    this.padding = const EdgeInsets.all(0),
  });
  @override
  _HorizontalCalendarState createState() => _HorizontalCalendarState();
}

class _HorizontalCalendarState extends State<HorizontalCalendar> {

  int selectedDay; // this is mutable

  @override
  void initState() {
    selectedDay = widget.selectedDate;
    super.initState();
  }
  1. 其次,我们可以将回调传递给DayWidget。
return DayWidget(
  day: index,
  dayName: DateFormat('EEEE').format(date).substring(0, 3),
  selected: selectedDay == index ? true : false, // modify this
  callback: (int day) { // Add this
    selectedDay = day;
    setState((){});
  },
);
  1. 终于可以在DayWidget中回调了:
onPressed: () {
  callback(day);
  // Here I should be able to change the selected date from
  // The HorizontalCalendar
},

这是结果:

  1. 完整代码
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

class HorizontalCalendar extends StatefulWidget {
  final double height;
  final double width;
  final EdgeInsets padding;
  final EdgeInsets margin;
  final int month;
  final int year;
  final int selectedDate; // this is immutable
  HorizontalCalendar({
    @required this.year,
    @required this.month,
    this.selectedDate,
    this.height,
    this.width,
    this.margin = const EdgeInsets.all(0),
    this.padding = const EdgeInsets.all(0),
  });
  @override
  _HorizontalCalendarState createState() => _HorizontalCalendarState();
}

class _HorizontalCalendarState extends State<HorizontalCalendar> {

  int selectedDay; // this is mutable

  @override
  void initState() {
    selectedDay = widget.selectedDate;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: widget.height,
      margin: widget.margin,
      padding: widget.padding,
      child: ListView.builder(
        scrollDirection: Axis.horizontal,
        itemCount: DateTime(widget.year, widget.month + 1, 0).day,
        itemBuilder: (context, index) {
          index = index + 1;
          DateTime date = DateTime(widget.year, widget.month, index);
          return DayWidget(
            day: index,
            dayName: DateFormat('EEEE').format(date).substring(0, 3),
            selected: selectedDay == index ? true : false,
            callback: (int day) {
              selectedDay = day;
              setState((){});
            },
          );
        },
      ),
    );
  }
}

class DayWidget extends StatelessWidget {
  final int day;
  final String dayName;
  final bool selected;
  final Function(int) callback;
  DayWidget({
    this.day,
    this.dayName,
    this.selected = false,
    this.callback,
  });
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(horizontal: 5),
      child: SizedBox(
        width: MediaQuery.of(context).size.width * 0.17,
        child: FlatButton(
          color: selected ? Colors.white : Colors.transparent,
          shape: new RoundedRectangleBorder(
            borderRadius: new BorderRadius.circular(15.0),
            side: BorderSide(
                color: selected ? Colors.white : Colors.grey,
                width: 1,
                style: BorderStyle.solid),
          ),
          onPressed: () {
            callback(day);
            // Here I should be able to change the selected date from
            // The HorizontalCalendar
          },
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              Text(
                dayName,
                style: TextStyle(
                  color: selected ? Colors.blueGrey : Colors.white60,
                  fontSize: 15,
                  fontWeight: selected ? FontWeight.w900 : FontWeight.w300,
                ),
              ),
              Text(
                day.toString(),
                style: TextStyle(
                  color: selected ? Colors.blueGrey : Colors.white,
                  fontSize: 24,
                  fontWeight: selected ? FontWeight.w900 : FontWeight.w500,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}