Flutter - CupertinoDatePicker initialDateTime updates only once

3.3k views Asked by At

I've created a CupertinoDatePicker widget, with an initial value set to a variable.

I want to update the selected value in the picker to that variable value when the user clicks on another widget in the screen - but it doesn't work (although the CupertinoDatePicker widget gets rebuilt).

Is it a bug or am I doing something wrong?

Code (can be copy-pasted into dartPad):

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

final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
final _time = DateTime.now();
int _min = 5;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  createState() => MyWidgetSate();
}

class MyWidgetSate extends State<MyWidget> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('_min = ' + _min.toString(), style: Theme.of(context).textTheme.headline4),
        _buildDurationPicker(context),
        RaisedButton(
            onPressed: () {
              print('hello');
              setState(() {
                _min += 5;
              });
            },
            child: const Text('Add', style: TextStyle(fontSize: 20)),
          ),
        ],
    );
  }
}

Widget _buildDurationPicker(BuildContext context) {
    DateTime initDateTime = DateTime(_time.year, _time.month, _time.day)
        .add(Duration(minutes: _min));
    return Container(
      height: 216.0,
      color: Colors.white,
      child: CupertinoDatePicker(
        mode: CupertinoDatePickerMode.time,
        use24hFormat: true,
        initialDateTime: initDateTime,
        backgroundColor: Colors.transparent,
        onDateTimeChanged: (DateTime date) {
          //
        },
      ),
    );
  }
2

There are 2 answers

1
Miguel Ruivo On BEST ANSWER

CupertinoDatePicker is maintaining state internally and only set the initialDateTime on its initState, despite you updating your widget's state.

To force a rebuild each time you set your initialDateTime, assign an UniqueKey() as a key of your CupertinoDatePicker and it will rebuild every time your state changes with a new initDateTime.

(...)
  CupertinoDatePicker(
        key: UniqueKey(),
        mode: CupertinoDatePickerMode.time,
        use24hFormat: true,
        initialDateTime: initDateTime,
        backgroundColor: Colors.transparent,
        onDateTimeChanged: (DateTime date) {
          //
        },
      ),
0
markcc On

I got insight from Miguel Ruivo and convert the UniqueKey() as a variable. Otherwise, the scroll effect will be laggy due to keep refreshing the timepicker. In this way, you can refresh the key by setState when it is needed.

Key _key = UniqueKey();

// update the unique key
(...)
setState(() {
    _key = UniqueKey();
});

(...)
CupertinoDatePicker(
    key: _key,
    mode: CupertinoDatePickerMode.time,
    use24hFormat: true,
    initialDateTime: initDateTime,
    backgroundColor: Colors.transparent,
    onDateTimeChanged: (DateTime date) {
      //
    },
  ),