flutter-flippable-box icon indicating copy to clipboard operation
flutter-flippable-box copied to clipboard

Saving front and back states to avoid widgets being rebuilt

Open Delgan opened this issue 4 years ago • 12 comments

Hi!

I just discovered your library and it's super useful, thanks for sharing!

I just encountered a small issue. It seems the front and back widgets are rebuilt when the card is flipped. I had a problem with this, especially when my child contained a FutureBuilder (despite the Future being created in initState()).

Do you think a solution is possible to save front and back states, like using a IndexedStack internally for example?

Delgan avatar Dec 26 '20 14:12 Delgan

Should be possible! tbh that was my first package and I haven't looked at it in a long time! Happy to take a PR on it if you figure out a nice way to make this work.

esDotDev avatar Dec 26 '20 17:12 esDotDev

Thanks for answering!

Actually, I would have liked to be able to open a PR instead of this ticket, but after a few tries I didn't manage to get the expected result. I had a weird bug with the animation of the AnimatedContainer occurring only while flipping from front to back.

In any case it's not very important. For my personal use I didn't need this transition so I just removed it. However I would love to see an "official" solution merged in your package, I'm sure it can be useful for others.

Delgan avatar Dec 26 '20 19:12 Delgan

Sure, thanks for the suggestion. If you have any code that shows it simply reproduced that could help when I find time to look at it.

As simple as just putting like a TextField on a card, typing something, and flipping it over I guess?

esDotDev avatar Dec 26 '20 19:12 esDotDev

I think what might work nicely is using the Visibility widget, and just set one of the children to offscreen.

esDotDev avatar Dec 26 '20 19:12 esDotDev

Yeah, here is a example:

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

class _MyWidgetState extends State<MyWidget> {
  @override
  void initState() {
    super.initState();
    print("Init state...");
  }

  @override
  Widget build(BuildContext context) {
    return Text("Front");
  }
}

class MyCard extends StatefulWidget {

  @override
  _MyCardState createState() => _MyCardState();
}

class _MyCardState extends State<MyCard> {
  bool _isFlipped = false;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      isFlipped: _isFlipped,
      onTap: () => setState(() => _isFlipped = !_isFlipped),
      child: FlippableBox(
        duration: 0.4,
        front: Container(
          height: 200,
          width: 300,
          color: Colors.red,
          child: MyWidget(),
        ),
        back: Container(
          height: 200,
          width: 300,
          color: Colors.blue,
          child: Text("Back"),
        ),
      ),
    );
  }
}

You will see that "Init state..." is printed each time the card is flipped to front.

The "workaround" I use is simply to replace in flippable_box.dart:

AnimatedBackground(
    decoration: bg,
    child: content,
)

with

IndexedStack(
    children: [front, back],
    index: value >= 90 ? 1 : 0,
)

Using Visibility might work especially as there is a maintainState attribute. However I would not know where to store the children.

Delgan avatar Dec 26 '20 21:12 Delgan

Hm, couldn't you just use a stack?:

Stack(children: [
  Visibility(visible: showChild1, maintainState: true, child: child1),
  Visibility(visible: !showChild1, maintainState: true, child: child2),
])

esDotDev avatar Dec 27 '20 05:12 esDotDev

Indeed, using Stack combined with Visibility should work the same way as the IndexedStack. However even in this case I didn't manage to make the animation happen in both directions.

Delgan avatar Dec 27 '20 10:12 Delgan

I see, ya I guess that's pretty much what IndexedStack is huh?? lol

esDotDev avatar Dec 27 '20 19:12 esDotDev

Probably yeah. :)

Delgan avatar Dec 27 '20 20:12 Delgan

@Delgan, @esDotDev Can you please assign me this issue I am happy to contribute this amazing package

  • There are multiple ways to achieve this, the following are the possible ways
    • I can achieve this using shared preferences to store the font and back reference
    • It is also possible to store front and back state reference in any Offline database, I probably go for the HIVE database

champ96k avatar Feb 11 '21 20:02 champ96k

Hey @champ96k, thanks for your commitment! About the implementation, I don't think it needs shared preference nor offline database. At least for the issue I described, it should be handled internally by the Widget state. It doesn't have to be more sophisticated than that.

Delgan avatar Feb 11 '21 22:02 Delgan

@Delgan Okay alright :)

champ96k avatar Feb 12 '21 23:02 champ96k