3

The code is a button that on pressed shows a modal bottom sheet (with showModalBottomSheet()) with a scrollable list of months that the user can pick, using a ListWheelScrollView widget (with method use.Delegate).

I was having trouble with the state that was not getting updated as the wheel was being scrolled, so I tried to print it. The print (available in the code) showed that the state is updating but really weirdly. I'm using Riverpod as a State Management solution, but I don't mind using stateful widgets, so if it's easier for you, don't hesitate.

I tried to print the state at multiple moments of the run in the console, but I can't understand the logic it follows.

If you could find a way to update the state, or if you know something that could help me, it would be amazing that you share it with me.

I tried to make my problem as minimal as I could so that you can find easily the heart of the issue. Here it is :

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

const List<String> _months = <String>[
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December'
];

void main() => runApp(ProviderScope(child: MyApp()));

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MainPage(),
    );
  }
}

int monthIndex = (DateTime.now().month);
final monthIndexProvider = StateProvider(((ref) => monthIndex));

class MainPage extends ConsumerWidget {
  const MainPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final int month = ref.watch(monthIndexProvider);

    return Scaffold(
      body: Center(
        child: ElevatedButton(
            child: Text(month.toString()),
            onPressed: () async {
              await showModalBottomSheet(
                context: context,
                builder: (BuildContext context) {
                  return Container(
                      height: 300,
                      child: ListWheelScrollView.useDelegate(
                          itemExtent: 50,
                          perspective: 0.001,
                          diameterRatio: 1.6,
                          physics: FixedExtentScrollPhysics(),
                          squeeze: 1.0,
                          overAndUnderCenterOpacity: 0.2,
                          useMagnifier: true,
                          magnification: 1.3,
                          onSelectedItemChanged: (index) {
                            ref.read(monthIndexProvider.notifier).state = index;
                            print(month); // This is the print where I want to get the state of month but it isn't the right one.
                          },
                          childDelegate: ListWheelChildBuilderDelegate(
                              childCount: 12,
                              builder: (context, index) {
                                return Container(
                                  child: Text(_months[index]),
                                );
                              })));
                },
              );
            }),
      ),
    );
  }
}
Mathieu
  • 35
  • 3
  • What do you mean by "really weirdly"? I tried your code and it seems it is working just fine – Hrvoje Čukman Oct 19 '22 at 11:14
  • If you look at the prints in the console, as you play with the wheel, you always get the same month index printed, which is weird because it updates on the button but when printed it is not updated : in the prints, I always get "I/flutter ( 3853): 10" (a value of 10) that should change, but doesn't and I think this is the origin of another bug I have in my bigger app. – Mathieu Oct 20 '22 at 06:14

1 Answers1

1

Inner state of showModalBottomSheet is not being updated. You can update it by using StatefulBuilder. More info here.

Here is the full solution:

final monthIndex = (DateTime.now().month);
final monthIndexProvider = StateProvider(((ref) => monthIndex));

class MainPage extends ConsumerWidget {
  const MainPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          child: Text(ref.watch(monthIndexProvider).toString()),
          onPressed: () async {
            await showModalBottomSheet(
              context: context,
              builder: (BuildContext context) {
                return StatefulBuilder(
                  builder: (BuildContext context, StateSetter setStateModal) {
                    final int month = ref.watch(monthIndexProvider);
                    return SizedBox(
                      height: 300,
                      child: ListWheelScrollView.useDelegate(
                        itemExtent: 50,
                        perspective: 0.001,
                        diameterRatio: 1.6,
                        physics: const FixedExtentScrollPhysics(),
                        squeeze: 1.0,
                        overAndUnderCenterOpacity: 0.2,
                        useMagnifier: true,
                        magnification: 1.3,
                        onSelectedItemChanged: (index) {
                          ref.read(monthIndexProvider.notifier).state = index;
                          setStateModal(() {});
                          print(month);
                        },
                        childDelegate: ListWheelChildBuilderDelegate(
                          childCount: 12,
                          builder: (context, index) {
                            return Text(_months[index]);
                          },
                        ),
                      ),
                    );
                  },
                );
              },
            );
          },
        ),
      ),
    );
  }
}
Hrvoje Čukman
  • 421
  • 4
  • 12