如何使用日期选择器时间轴和控制器(颤动)为当前选定的日期设置动画?

How to animate to current selected date using date picker timeline and controller (flutter)?

我正在使用日期选择器时间轴来显示水平和可滚动的日期选择器(flutter 包:https://pub.dev/packages/date_picker_timeline)。对应代码:

class HomeDatePicker extends StatelessWidget {
  const HomeDatePicker({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      key: Provider.of<DateKeyProvider>(context).key,
      child: DatePicker(
        DateTime.now(),
        initialSelectedDate:
            Provider.of<DateProvider>(context).getDate,
        height: 80.0,
        daysCount: 14,
        selectionColor: Colors.black54,
        onDateChange: (date) {
          Provider.of<DateProvider>(context, listen: false).changeDate(date);
        },
      ),
    );
  }
}

日期选择器在主屏幕上,用户可以在另一个屏幕上使用提供程序包更改日期。当第二个屏幕弹出时,我使用一个键强制小部件重建,以便在日期选择器中也选择了新秘密的日期。但是,日期选择器不会自动滚动到正在选择的日期。我尝试使用包提供的 controller.animateTo() ,但我真的不知道在哪里调用它。在他们的示例中,他们使用了一个调用函数的按钮,但我想在再次加载小部件时为所选日期设置动画。

这里是包中的示例代码:

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Date Picker Timeline Demo'),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  DatePickerController _controller = DatePickerController();

  DateTime _selectedValue = DateTime.now();


  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.replay),
        onPressed: () {
          _controller.animateToSelection();
        },
      ),
        appBar: AppBar(
          title: Text(widget.title!),
        ),
        body: Container(
          padding: EdgeInsets.all(20.0),
          color: Colors.blueGrey[100],
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text("You Selected:"),
              Padding(
                padding: EdgeInsets.all(10),
              ),
              Text(_selectedValue.toString()),
              Padding(
                padding: EdgeInsets.all(20),
              ),
              Container(
                child: DatePicker(
                  DateTime.now(),
                  width: 60,
                  height: 80,
                  controller: _controller,
                  initialSelectedDate: DateTime.now(),
                  selectionColor: Colors.black,
                  selectedTextColor: Colors.white,
                  inactiveDates: [
                    DateTime.now().add(Duration(days: 3)),
                    DateTime.now().add(Duration(days: 4)),
                    DateTime.now().add(Duration(days: 7))
                  ],
                  onDateChange: (date) {
                    // New date selected
                    setState(() {
                      _selectedValue = date;
                    });
                  },
                ),
              ),
            ],
          ),
        ));
  }
}

你们知道如何解决这个问题吗?我很确定这是因为我正在使用密钥并且我无法将控制器附加到构建中的某些东西但我不知道如何解决它。当 Provider.of(context).getDate 发生变化时,小部件未重建...

我试过类似的东西:

class HomeDatePicker extends StatefulWidget {
  const HomeDatePicker({Key? key}) : super(key: key);

  @override
  State<HomeDatePicker> createState() => _HomeDatePickerState();
}

class _HomeDatePickerState extends State<HomeDatePicker> {
  DatePickerController _controller = DatePickerController();

  @override
  void initState() {
    _controller.animateToDate(
      Provider.of<DateProvider>(context, listen: false).getDate,
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      key: Provider.of<DateKeyProvider>(context).key,
      child: DatePicker(
        DateTime.now(),
        initialSelectedDate:
            Provider.of<DateProvider>(context, listen: false).getDate,
        height: 80.0,
        daysCount: 14,
        selectionColor: Colors.black54,
        onDateChange: (date) {
          Provider.of<DateProvider>(context, listen: false).changeDate(date);
        },
        controller: _controller,
      ),
    );
  }
}

它不断产生 'DatePickerController is not attached to any DatePicker View' 的错误消息。当我使用:

WidgetsBinding.instance
        .addPostFrameCallback((_) => yourFunction(context));

它根本没有动画,但没有错误消息。

当我将 controller.animateTo() 添加到延迟中时,它起作用了:

Future.delayed(const Duration(seconds: 1), () {
      _controller.animateToDate(
          Provider.of<DateProvider>(context, listen: false).getDate);
    });

但这不是我想要的干净解决方案。

我找到了解决方案,以防有人遇到类似情况。我很确定它适用于任何滚动控制器。

class HomeDatePicker extends StatelessWidget {
  final DatePickerController _controller = DatePickerController();

  HomeDatePicker({Key? key}) : super(key: key);

  void executeAfterBuild() {
    _controller.animateToSelection();
  }

  @override
  Widget build(BuildContext context) {
    WidgetsBinding.instance!.addPostFrameCallback((_) => executeAfterBuild());

    return Container(
      key: Provider.of<DateKeyProvider>(context).key,
      child: DatePicker(
        DateTime.now(),
        initialSelectedDate: Provider.of<DateProvider>(context).getDate,
        height: 80.0,
        daysCount: 14,
        selectionColor: Colors.black54,
        onDateChange: (date) {
          Provider.of<DateProvider>(context, listen: false).changeDate(date);
        },
        monthTextStyle: const TextStyle(
          fontSize: 11.0,
          fontWeight: FontWeight.bold,
        ),
        dayTextStyle: const TextStyle(
          fontSize: 11.0,
          fontWeight: FontWeight.bold,
        ),
        dateTextStyle: const TextStyle(
          fontSize: 21.0,
          fontWeight: FontWeight.bold,
        ),
        controller: _controller,
      ),
    );
  }
}