Only showing the front side when pressing the nextButton of a flash card app using the flip_card dependency [FLUTTER]
So here's what I added to my code to make sure every time the user decides to see the next card, it shows the front side of the next card, not the back side:
First I defined a global variable:
GlobalKey<FlipCardState> cardKey = GlobalKey<FlipCardState>();
then it's passed to the key
property of flip_card package:
FlipCard(
key: cardKey,
Then I use the variable to check the status of card whether the front of card is shown or the back, if the back side is shown then it will be toggled to show the front side of the next card when clicking on the "next card button":
onPressed: () {
if(cardKey.currentState != null) { //null safety
if (!cardKey.currentState!.isFront) {
cardKey.currentState!.toggleCard();
}
}
},
Adding to the onPressed
property of the "next card" button.
Admin
Updated on December 11, 2022Comments
-
Admin over 1 year
I have a flashcard app using flutter in android studio, I am very new at android studio and flutter. So every time the user flips, it shows the back side of the card. If the card is showing the back side while the user is pressing the next button, the card automatically shows the back side of the proceeding cards. What i wanted to do is only show the front side each time the user presses the next button.
I have 3 classes, a flip_card.dart [my animations], Flash.dart [buttons, widgets, front/back image lists, etc.], main.dart [main, only calls the class]. I do not know what to do, either call the animation when it is played to a function? or to call a local "bool isFront" inside the animation when it is played. this is my whole flip_dart.dart library flip_card; import 'dart:math'; import 'package:flutter/material.dart'; import 'Flash.dart'; enum FlipDirection { VERTICAL, HORIZONTAL, } class AnimationCard extends StatelessWidget { AnimationCard({this.child, this.animation, this.direction}); final Widget child; final Animation<double> animation; final FlipDirection direction; @override Widget build(BuildContext context) { return AnimatedBuilder( animation: animation, builder: (BuildContext context, Widget child) { var transform = Matrix4.identity(); transform.setEntry(3, 2, 0.001); if (direction == FlipDirection.VERTICAL) { transform.rotateX(animation.value); } else { transform.rotateY(animation.value); } return Transform( transform: transform, alignment: Alignment.center, child: child, ); }, child: child, ); } } class FlipCard extends StatefulWidget { final Widget front; final Widget back; final int speed = 500; final FlipDirection direction; const FlipCard( {Key key, @required this.front, @required this.back, this.direction = FlipDirection.HORIZONTAL}) : super(key: key); @override State<StatefulWidget> createState() { return _FlipCardState(); } } class _FlipCardState extends State<FlipCard> with SingleTickerProviderStateMixin { AnimationController controller; Animation<double> _frontRotation; Animation<double> _backRotation; bool isFront = true; @override void initState() { super.initState(); controller = AnimationController( duration: Duration(milliseconds: widget.speed), vsync: this); _frontRotation = TweenSequence( <TweenSequenceItem<double>>[ TweenSequenceItem<double>( tween: Tween(begin: 0.0, end: pi / 2) .chain(CurveTween(curve: Curves.linear)), weight: 50.0, ), TweenSequenceItem<double>( tween: ConstantTween<double>(pi / 2), weight: 50.0, ), ], ).animate(controller); _backRotation = TweenSequence( <TweenSequenceItem<double>>[ TweenSequenceItem<double>( tween: ConstantTween<double>(pi / 2), weight: 50.0, ), TweenSequenceItem<double>( tween: Tween(begin: -pi / 2, end: 0.0) .chain(CurveTween(curve: Curves.linear)), weight: 50.0, ), ], ).animate(controller); } _toggleCard() { if (isFront) { controller.forward(); // if(_nextImage()){ // // } } else { controller.reverse(); } isFront = !isFront; } @override Widget build(BuildContext context) { return GestureDetector( onTap: _toggleCard, child: Stack( fit: StackFit.expand, children: <Widget>[ AnimationCard( animation: _frontRotation, child: widget.front, direction: widget.direction, ), AnimationCard( animation: _backRotation, child: widget.back, direction: widget.direction, ), ], ), ); } @override void dispose() { controller.dispose(); super.dispose(); } } And this is my Flash.dart import 'flip_card.dart'; import 'package:flutter/material.dart'; class Flashcard extends StatefulWidget { @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<Flashcard> { int photoIndex = 0; //startfirstpage bool isFront = true; var playerProgress = 0; List<String> photos = [ //front 'assets/c1v1f.png', 'assets/c1v2f.png', 'assets/c1v3f.png', 'assets/c1v4f.png', 'assets/c1v5f.png', 'assets/c1v6f.png', 'assets/c1v7f.png', 'assets/c1v8f.png', 'assets/c1v9f.png', 'assets/c1v10f.png', ]; List<String> photos1 = [ //back 'assets/c1v1b.png', 'assets/c1v2b.png', 'assets/c1v3b.png', 'assets/c1v4b.png', 'assets/c1v5b.png', 'assets/c1v6b.png', 'assets/c1v7b.png', 'assets/c1v8b.png', 'assets/c1v9b.png', 'assets/c1v10b.png', ]; var bookmarkicon = "assets/bookmarkoff.png"; var bookmarkOff = "assets/bookmarkoff.png"; var bookmarkOn = "assets/bookmarkon.png"; void _previousImage() { // prev setState(() { photoIndex = photoIndex > 0 ? photoIndex - 1 : 0; }); } void _nextImage() { // next setState(() { photoIndex = photoIndex < photos.length - 1 ? photoIndex + 1 : photoIndex; playerProgress += 10; print(playerProgress); print(photoIndex); // if(isFront){ // photoIndex--; // } Flashcard(); }); } @override Widget build(BuildContext context) { return new Scaffold( //title_page appBar: new AppBar( title: new Text('Category 時'), centerTitle: true, ), body: Column( //content mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Center( child: Stack( children: <Widget>[ Container( child: FlipCard( direction: FlipDirection.HORIZONTAL, front: Material( //front_side child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(25.0), image: DecorationImage( image: AssetImage(photos[photoIndex]), //images front fit: BoxFit.cover)), ), elevation: 20.0, borderRadius: BorderRadius.all(Radius.circular(40.0)), ), back: Material( //back_side child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(25.0), image: DecorationImage( image: AssetImage(photos1[photoIndex]), // images back fit: BoxFit.cover)), ), elevation: 20.0, borderRadius: BorderRadius.all(Radius.circular(40.0)), ), ), height: 400.0,//flashcard width: 370.0, ), Positioned( top: 380.0, //dots left: 25.0, right: 25.0, child: SelectedPhoto(numberOfDots: photos.length, photoIndex: photoIndex), ) ], ), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RaisedButton( child: Text('Prev', textScaleFactor: 1.3,), onPressed: _previousImage, elevation: 10.0, color: Colors.redAccent, textColor: Colors.white, ), SizedBox(width: 10.0), //space ButtonTheme( //bookmark minWidth: 10, height: 10, child: RaisedButton( child: Image.asset(bookmarkicon, scale: 3.5,), color: Colors.transparent, onPressed: (){ if(this.bookmarkicon=='assets/bookmarkoff.png'){ print(this.bookmarkicon +" is clicked"); setState(() { bookmarkicon = bookmarkOn; }); this.bookmarkicon = 'assets/bookmarkon.png'; } else if(this.bookmarkicon=='assets/bookmarkon.png'){ print(this.bookmarkicon +" is clicked"); this.bookmarkicon = 'assets/bookmarkoff.png'; setState(() { bookmarkicon = bookmarkOff; }); } //any implementation for bookmark will be here ;) }, ), ), SizedBox(width: 10.0), //space RaisedButton( child: Text('Next', textScaleFactor: 1.3,), onPressed:_nextImage, elevation: 10.0, color: Colors.redAccent, textColor: Colors.white, ) ], ) ], )); } } class SelectedPhoto extends StatelessWidget { final int numberOfDots; final int photoIndex; SelectedPhoto({this.numberOfDots, this.photoIndex}); Widget _inactivePhoto() { return new Container( child: new Padding( padding: const EdgeInsets.only(left: 3.0, right: 3.0), child: Container( height: 8.0, width: 8.0, decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(4.0) ), ), ) ); } Widget _activePhoto() { return Container( child: Padding( padding: EdgeInsets.only(left: 3.0, right: 3.0), child: Container( height: 10.0, width: 10.0, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(5.0), boxShadow: [ BoxShadow( color: Colors.grey, spreadRadius: 0.0, blurRadius: 2.0 ) ] ), ), ), ); } List<Widget> _buildDots() { List<Widget> dots = []; for(int i = 0; i< numberOfDots; ++i) { dots.add( i == photoIndex ? _activePhoto(): _inactivePhoto() ); } return dots; } @override Widget build(BuildContext context) { return new Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: _buildDots(), ), ); } }
The code works, but when the user pressed next, it will display the next card even though it is the back side showing.