Home > Back-end >  Flutter : Scrolling a ListWheelScrollView, can't get the state of the selected item
Flutter : Scrolling a ListWheelScrollView, can't get the state of the selected item

Time:10-20

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]),
                                );
                              })));
                },
              );
            }),
      ),
    );
  }
}

CodePudding user response:

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]);
                          },
                        ),
                      ),
                    );
                  },
                );
              },
            );
          },
        ),
      ),
    );
  }
}
  • Related