federicoviceconti / card_stack_widget

Stack of cards, built in Dart+Flutter
https://pub.dev/packages/card_stack_widget
MIT License
21 stars 1 forks source link

The order of the cards reset when setState is triggered #2

Closed luis-cruzt closed 1 year ago

luis-cruzt commented 1 year ago

Hello, the order of the cards resets to the initial order when i call setState is there anyway to keep the current order?

Thanks.

federicoviceconti commented 1 year ago

Can I have the sample code you used in order to replicate the issue?

Thanks.

luis-cruzt commented 1 year ago

Sure, there you go:

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

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: [
          Expanded(
            child: CardStackWidget(
              opacityChangeOnDrag: true,
              swipeOrientation: CardOrientation.both,
              cardDismissOrientation: CardOrientation.both,
              positionFactor: 3,
              scaleFactor: 1.5,
              alignment: Alignment.center,
              reverseOrder: true,
              animateCardScale: true,
              dismissedCardDuration: const Duration(milliseconds: 900),
              cardList: [
                CardModel(
                  backgroundColor: Colors.blue,
                  radius: const Radius.circular(8),
                  shadowColor: Colors.black.withOpacity(0.2),
                  child: const SizedBox(
                    width: 200,
                    height: 300,
                    child: Text('data'),
                  ),
                ),
                CardModel(
                  backgroundColor: Colors.black,
                  radius: const Radius.circular(8),
                  shadowColor: Colors.black.withOpacity(0.2),
                  child: const SizedBox(
                    width: 200,
                    height: 300,
                    child: Text('data'),
                  ),
                ),
              ],
            ),
          ),
          SafeArea(
            child: MaterialButton(
              onPressed: () {
                setState(() {
                });
              },
              child: const Text('Action'),
            ),
          )
        ],
      ),
    );
  }
}
luis-cruzt commented 1 year ago

Here is a video too, just press the button at the bottom and it will trigger the setState https://user-images.githubusercontent.com/55716036/217903553-5042597b-8d6e-4113-b353-fd6f7086256d.MOV

federicoviceconti commented 1 year ago

Hi @luis-cruzt, I tried your code and you have to move your card list as instance parameter. An example:

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

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  // The list is here
  final List<CardModel> _cardList = [
    CardModel(
      backgroundColor: Colors.red,
      radius: const Radius.circular(8),
      shadowColor: Colors.black.withOpacity(0.2),
      child: const SizedBox(
        width: 200,
        height: 300,
        child: Text('data'),
      ),
    ),
    CardModel(
      backgroundColor: Colors.blue,
      radius: const Radius.circular(8),
      shadowColor: Colors.black.withOpacity(0.2),
      child: const SizedBox(
        width: 200,
        height: 300,
        child: Text('data'),
      ),
    ),
    CardModel(
      backgroundColor: Colors.black,
      radius: const Radius.circular(8),
      shadowColor: Colors.black.withOpacity(0.2),
      child: const SizedBox(
        width: 200,
        height: 300,
        child: Text('data'),
      ),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: [
          Expanded(
            child: CardStackWidget(
              opacityChangeOnDrag: true,
              swipeOrientation: CardOrientation.both,
              cardDismissOrientation: CardOrientation.both,
              positionFactor: 3,
              scaleFactor: 1.5,
              alignment: Alignment.center,
              reverseOrder: true,
              animateCardScale: true,
              dismissedCardDuration: const Duration(milliseconds: 900),
              cardList: _cardList, // <-- use the instance parameter
            ),
          ),
          SafeArea(
            child: MaterialButton(
              onPressed: () {
                setState(() {});
              },
              child: const Text('Action'),
            ),
          )
        ],
      ),
    );
  }
}
luis-cruzt commented 1 year ago

But if i need to to update information inside the CardModel it would not work:

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

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  var data = '1';
  var cardList2 = <CardModel>[];

  @override
  void initState() {
    cardList2 = [
      CardModel(
        backgroundColor: Colors.blue,
        radius: const Radius.circular(8),
        shadowColor: Colors.black.withOpacity(0.2),
        child: SizedBox(
          width: 200,
          height: 300,
          child: Text(data),
        ),
      ),
      CardModel(
        backgroundColor: Colors.red,
        radius: const Radius.circular(8),
        shadowColor: Colors.red.withOpacity(0.2),
        child: const SizedBox(
          width: 200,
          height: 300,
          child: Text('data'),
        ),
      ),
    ];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: [
          Expanded(
            child: CardStackWidget(
              opacityChangeOnDrag: true,
              swipeOrientation: CardOrientation.both,
              cardDismissOrientation: CardOrientation.both,
              positionFactor: 3,
              scaleFactor: 1.5,
              alignment: Alignment.center,
              reverseOrder: true,
              animateCardScale: true,
              dismissedCardDuration: const Duration(milliseconds: 900),
              cardList: cardList2,
            ),
          ),
          SafeArea(
            child: MaterialButton(
              onPressed: () {
                setState(() {
                  data = '3';
                });
              },
              child: const Text('Action'),
            ),
          )
        ],
      ),
    );
  }
}
luis-cruzt commented 1 year ago

I ended up using Riverpod to handle the state of each cardModel and it's now working as intended, thank you for your time!

You can close this issue if you feel like it needs to.