Fliping just one direction - flutter

In flutter there is a pack for flipping card, But when tap its first view - turns into second view. Same as, its turn into second to first view.
But I want to turn into first to second only. Not again reversible.How can I make it, pls.

You can also configure the card to only flip when desired by using a GlobalKey to toggle the cards:
GlobalKey<FlipCardState> cardKey = GlobalKey<FlipCardState>();
#override
Widget build(BuildContext context) {
return FlipCard(
key: cardKey,
flipOnTouch: false,
front: Container(
child: RaisedButton(
onPressed: () => cardKey.currentState.toggleCard(),
child: Text('Toggle'),
),
),
back: Container(
child: Text('Back'),
),
);
}
You can do some logic to togglecard once and then the change the onPressed to an empty function

Related

Flutter - Screen focus on a certain widget

I need help to do the following: when I press List 1, the screen focuses on List 1; I need the same for the rest of the options
This is the code for the example:
code
This behavior already exists in web pages but I haven't found this same behavior at the mobile app level. Thank you
Here is a small code snippet of something similar which might help you achieve you desired results.
By clicking the fab icon it will scroll down to item 35 within the ListView.
class MyHomePage extends StatelessWidget {
final _scrollController = ScrollController();
final _cardHeight = 200.0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.orange,
onPressed: () => _animateToIndex(35),
child: Icon(Icons.add),
),
body: ListView.builder(
controller: _scrollController,
itemCount: 100,
itemBuilder: (_, i) => Container(
height: _cardHeight,
child: Card(
color: Colors.lightBlue,
child: Center(
child: Text("Scroll Item $i", style: TextStyle(fontSize: 28.0),),
),
),
),
),
);
}
_animateToIndex(index) {
_scrollController.animateTo(_cardHeight * index,
duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn);
}
}
You'll need to have a scrollable Widget (like ListView, SingleScrollableWidget) instead of a Column in ListSecondPage.
Then add a ScrollController to it and ListSecondPage should receive which button was tapped. Based on that selection you can scroll to the desired location with the ScrollController

Flutter - How to flip the previous card back using FlipCard

After days of search I'm getting help.
I work on a flutter application.
Context:
A grid view feeded with Json
-childs : GridTile with Flipcard in (https://pub.dev/packages/flip_card)
-On tap on GridTile there is a callback to get the selected Item and an animation because of the flipcard onTap
What I would:
When an item is aleready selected (flipcard flipped so we show the back of the card),
And I selected another item of the grid te(so flipcard of this itme also flipped)
I would like to flip back the old selected item Flipcard without rebuild the tree because I would lost the state of the new selected item.
I tried many thing. For example I tried to use GlobalKey on GridTiles to interract with after build but currentState is always null when I want to interact with.
I wonder what is the good practice in this case ?
I hope I was clear :) (I'm french)
Thank you the community!
.
Something to know...
It is possible to interract with the flipcard (child of gridtile) like this
(GlobalKey)
GlobalKey<FlipCardState> cardKey = GlobalKey<FlipCardState>();
#override
Widget build(BuildContext context) {
return FlipCard(
key: cardKey,
flipOnTouch: false,
front: Container(
child: RaisedButton(
onPressed: () => cardKey.currentState.toggleCard(),
child: Text('Toggle'),
),
),
back: Container(
child: Text('Back'),
),
);
}
I'm not sure if I understood your question, but here is an example of how you could use a GridView with FlipCards:
var cardKeys = Map<int, GlobalKey<FlipCardState>>();
GlobalKey<FlipCardState> lastFlipped;
Widget _buildFlipCard(String text, Color color, int index) {
return SizedBox(
height: 120.0,
child: Card(
color: color,
child: Center(
child:
Text(text, style: TextStyle(color: Colors.white, fontSize: 20.0)),
),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("FlipCards")),
body: GridView.builder(
itemCount: 20,
itemBuilder: (context, index) {
cardKeys.putIfAbsent(index, () => GlobalKey<FlipCardState>());
GlobalKey<FlipCardState> thisCard = cardKeys[index];
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FlipCardWithKeepAlive(
child: FlipCard(
flipOnTouch: false,
key: thisCard,
front: _buildFlipCard("$index", Colors.blue, index),
back: _buildFlipCard("$index", Colors.green, index),
onFlip: () {
if (lastFlipped != thisCard) {
lastFlipped?.currentState?.toggleCard();
lastFlipped = thisCard;
}
},
),
),
RaisedButton(
child: Text("Flip Card"),
onPressed: () => cardKeys[index].currentState.toggleCard(),
)
],
);
},
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
),
);
}
class FlipCardWithKeepAlive extends StatefulWidget {
final FlipCard child;
FlipCardWithKeepAlive({Key key, this.child}) : super(key: key);
#override
State<StatefulWidget> createState() => FlipCardWithKeepAliveState();
}
class FlipCardWithKeepAliveState extends State<FlipCardWithKeepAlive>
with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
super.build(context);
return widget.child;
}
#override
bool get wantKeepAlive => true;
}
You need to use a different key for each element of the list, I used a Map in this case.
I also wrapped the FlipCard with a custom FlipCardWithKeepAlive stateful widget that uses AutomaticKeepAliveClientMixin to keep alive the FlipCard while scrolling.
Edit: I updated the code so when you flip one card, the previous card flipped gets flipped back. Basically you need to save the last flipped card and when a new one is flipped, flip the last one and put the new one as last flipped.
The code will make both cards flip at the same time, if you want one card to wait the other use onFlipDone() instead of onFlip(), like this:
onFlipDone: (isFront) {
bool isFlipped = !isFront;
if (isFlipped && lastFlipped != thisCard) {
lastFlipped?.currentState?.toggleCard();
lastFlipped = thisCard;
}
}

Interact with lower widget in Stack

I have a Stack that has a GoogleMap and an overlapping SingleChildScrollView, filled with Widgets.
However, the SCSV now block the map, and I can't interact with it? What I am trying to do, is a map as "upper" widget on the page and then the scrollview can be scrolled over the map.
Stack(children: <Widget>[
Container(
height: 400,
child: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition:
CameraPosition(target: _center, zoom: 13.0),
)),
SingleChildScrollView(
child: Padding(
padding: EdgeInsets.fromLTRB(0, 300, 0, 0),
child: Container(
decoration: BoxDecoration(color: Colors.white),
child: Column(children: _offers))))
])
Any idea how I can make this happen? Other suggestions than my existing layout are more than welcome, as long as the results is the same :)
I think you had the same problem as I solved in my application. I created a stack of two interactive widgets in my photo preview — pan/draw — and wanted to allow users to switch the interaction between them. As they are all full-screen widgets, I need to make the "top" one be sometimes transparent for the user's clicks, depends on a boolean flag (panEnable in my case).
I solved that with the IgnorePointer widget:
class PhotoPreviewScreen extends StatefulWidget {
_PhotoPreviewScreen createState() => _PhotoPreviewScreen();
}
class _PhotoPreviewScreen extends State<PhotoPreviewScreen> {
bool panEnable = true; // THAT IS THE enable/disable flag
final String imagePath = 'my_image.jpg'; // image to show and interact with
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
InteractiveViewer( // This is the "lower widget"
panEnabled: panEnable, // THAT IS THE enable/disable flag
scaleEnabled: panEnable, // THAT IS THE enable/disable flag
boundaryMargin: EdgeInsets.all(double.infinity),
minScale: 1,
maxScale: 16,
child: Image.file(
File(imagePath), // imagePath — local path to an image in Preview
),
),
Center(
child: Stack(
children: <Widget>[
IgnorePointer(
ignoring: panEnable, // THAT IS THE enable/disable flag
child:
SomeFullScreenActionWidget( // AN UPPER ACTION
onPressed: () => <SOME ACTION>,
), // SomeFullScreenActionWidget
), // IgnorePointer
// <here might be some "passive" widgets that are not use pointers
], // children of Stack widget
), // Stack
), // Center
IconButton( // wrap it in Align/Positioned or any other widget to arrange the widgets switch button on the screen
iconSize: 33.0,
color: Colors.white,
icon: Icon(!panEnable? CupertinoIcons.pencil_outline: CupertinoIcons.pencil_slash), // I use some stylish icons, you may choose standard
onPressed: () {
setState(() {
panEnable = !panEnable; // HERE IS THE SWITCH enable/disable flag
}); // SetState
}, // onPressed
), // IconButton
], // children of Stack
), // Stack
); // Scaffold
That is important to mention that I use a StatefulWidget class to use setState(). In the case of a StatelessWidget class, it would not work.

Flutter ReorderableListView doesn't work with TextFields

The widgets in my ReorderableListView are essentially TextFields. When long pressing on a widget, after the time when the long press should cause the widget to "hover," instead the TextField receives focus. How can I make the drag & drop effect take precedence over the TextField? I would still like a normal tap to activate the TextField.
The code below demonstrates my issue.
I also tried to use this unofficial flutter_reorderable_list package. (To test this one, replace the Text widget on this line of the example code with a TextField.)
I'm willing to use any ugly hacks to get this working, including modifying the Flutter source code!
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final children = List<Widget>();
for (var i = 0; i < 5; i++) {
children.add(Container(
color: Colors.pink, // Only the pink area activates drag & drop
key: Key("$i"),
height: 50.0,
child: Container(
color: Colors.grey,
margin: EdgeInsets.only(left: 50),
child: TextField(),
),
));
}
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: ReorderableListView(
children: children,
onReorder: (oldIndex, newIndex) => null,
),
),
),
);
}
}
You need to do multiple things in there to fix this.
First disable the default handler in ReorderableListView by setting buildDefaultDragHandles: false in its properties.
Wrap you child widget inside ReorderableDragStartListener widget like this
ReorderableDragStartListener(
index: i,
child: Container(
color: Colors.grey,
margin: EdgeInsets.only(left: 50),
child: TextFormField(initialValue: "Child $i", ),
),
),
Then inside this ReorderableDragStartListener wrap your child in InkWell and AbsorbPointer. Then use FocusNode to focus inner TextField on single tap.
Like this
InkWell(
onTap: () => _focusNode.requestFocus(),
onLongPress: () {
print("long pressed");
},
child: AbsorbPointer(
child: TextFormField(initialValue: "Child $i", focusNode: _focusNode,),
),
),
You need to create multiple FocusNode for all the items in list. You can do this by using List or by simpling creating a new FocusNode inside the loop.
Complete code example here https://dartpad.dev/?id=e75b493dae1287757c5e1d77a0dc73f1

Navigator gets the wrong context

I have a flutter application which shows a camera, then scans a qr-code using git://github.com/arashbi/flutter_qrcode_reader and on the call back, I want to navigate to another screen to show the information I get from some query. The problem is, it seems Navigator get a wrong context, so instead of full page navigation, I see the second page pushed inside my first page as a widget.
The build of first page is as follow :
#override
Widget build(BuildContext context) {
Widget main =
new Scaffold(
appBar: _buildAppBar(),
body: Column(
children: <Widget>[
_eventButton ?? new Text(""),
new Center(
child: new Text("Hi"))
],
),
floatingActionButton: new FloatingActionButton(
onPressed:
() {
new QRCodeReader()
.setAutoFocusIntervalInMs(200)
.setForceAutoFocus(true)
.setTorchEnabled(true)
.setHandlePermissions(true)
.setExecuteAfterPermissionGranted(true)
.scan().then((barcode) => _showTicketPage(barcode));
}
,
child: new Icon(Icons.check),
),
);
if (!_loading) {
return main;
} else {
return new Stack(
children: [main,
new Container(
decoration: new BoxDecoration(
color: Color.fromRGBO(220, 220, 220,
0.3) // Specifies the background color and the opacity
),
child: new Center(child: new CircularProgressIndicator(),))
]
);
}
}
The 'Hi' Widget is for debugging, and the navigate method is
void _showTicketPage(var barcode) {
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) => TicketScreen(barcode)));
}
After getting the barcode, the second screen - TicketScreen - is pushed under 'Hi' Widget. I didn't even know this was possible to do.
I tried to get the context of the screen, save it to a field var, but that didn't help either.
How can I fix it? I ran out of ideas.