nixrajput / flutter_carousel_widget

A customizable carousel slider widget in Flutter which supports infinite scrolling, auto scrolling, custom child widget, custom animations and built-in indicators.
https://pub.dev/packages/flutter_carousel_widget
MIT License
27 stars 16 forks source link

Stateful widget not being restored with ValueKey #16

Open melio-matt opened 1 year ago

melio-matt commented 1 year ago

Hello I've created a carousel by supplying an array of stateful widgets and when the provider signals, this will be reconstructed as part of the normal build process. On the rebuild and the array changing dimension I loose the state of my widgets, which do have ValueKeys on each. Switching the key to a GlobalKey means I retain the state, but there are obvious reasons for not wanting to use GlobalKeys. I didn't find anything in the documentation about this, so I assumed that it should work the same way as other lists where the position of a widget can be changed using local keys. regards Matthew

nixrajput commented 1 year ago

Hi @melio-matt

Can you please provide some test cases or any screenshots or a video that how are you implementing it and what are you trying to do?

Thanks Nikhil

melio-matt commented 1 year ago

Hi @nixrajput

I've added below some code that illustrates what I'm doing. The floating button when clicked alters the state and removes one of the pages from the carousel. Before pressing this, navigate to the last page and enter some text into the box, then press the button. You will then see the input box no longer has the text present. There is some commented out code that switches out the local and global keys. Once swapped round and you repeat the above action you will see the text is maintained in the input box.

regards Matthew

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

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

GlobalKey inputScreenGlobalKey = GlobalKey();

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Carousel State Test'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  CarouselController carouselController = CarouselController();
  bool _itemsAltered = false;

  void _alterItems() {
    setState(() {
      _itemsAltered = !_itemsAltered;
    });
  }

  @override
  Widget build(BuildContext context) {
    List<Widget> carouselItems = [];
    carouselItems.add(const Text("panel 1", key: ValueKey("panel1")));
    if (_itemsAltered == false) {
      carouselItems.add(const Text("panel 2", key: ValueKey("panel2")));
    }

    // swap these lines to move between local keys and global keys
    carouselItems.add(const InputScreen(key: ValueKey("inputScreen")));
    // carouselItems.add(InputScreen(key: inputScreenGlobalKey));

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: FlutterCarousel(
          items: carouselItems,
          options: CarouselOptions(),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _alterItems,
        tooltip: 'Alter',
        child: const Icon(Icons.ac_unit),
      ),
    );
  }
}

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

  @override
  State<StatefulWidget> createState() {
    return _InputScreenState();
  }
}

class _InputScreenState extends State<InputScreen> {
  late TextEditingController textEditingController;

  @override
  void initState() {
    super.initState();
    textEditingController = TextEditingController();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: textEditingController,
    );
  }
}
nixrajput commented 1 year ago

Hi @melio-matt

I will look into this and I will definitely revert back to you after testing and solution.

Please have some patience.

Thanks and regards, Nikhil

melio-matt commented 1 year ago

Thanks @nixrajput

No massive urgency, I have a solution that works for me at the moment and will be easy enough to put back in the more permanent solution.

Matthew