I am trying to implement a swipable cards (similar to the Tinder app) using a Draggable
widget. The swiping works fine except that I am struggling with figuring out how to set the size of the Draggable
's feedback
to have an equal size as the child
. The issue is that the Stack
widget holding the Draggable
items have a dynamic size depending on the screen size and therefore setting the size to a fixed value is not an option.
I was trying to use the LayoutBuilder with hope that I will be able to obtain the size using RenderBox box = context.findRenderObject() as RenderBox;
with following exception RenderBox was not laid out
. After reading the docs, it turned out that getting the RenderBox cannot be called in the build
function.
Another option could be to use MediaQuery.of(context).size
, however this is not that convenient as it returns only the window size where the app is rendered (whole screen).
I would really appreciate if somebody could give me a clue how this can be done.
Code:
class CardStack extends StatefulWidget {
@override
_CardStackState createState() => new _CardStackState();
}
class _CardStackState extends State<StatefulWidget> {
@override
Widget build(BuildContext context) {
return new Container(
padding: EdgeInsets.all(32),
child: SizedBox.expand(
child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
RenderBox box = context.findRenderObject() as RenderBox;
return new Stack(
children: <Widget>[
new Draggable(
key: ObjectKey('card1'),
child: new Card(
color: Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Container(
),
),
feedback: new Card(
color: Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Container(
width: box.size.width, // TODO: how to get same size as child??
height: box.size.height, // TODO: how to get same size as child??
),
),
childWhenDragging: Container(),
),
new Draggable(
key: ObjectKey('card2'),
child: new Card(
color: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Container(
),
),
feedback: new Card(
color: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Container(
width: box.size.width,
height: box.size.height,
),
),
childWhenDragging: Container(),
),
new Listener(
onPointerDown: (PointerDownEvent event) {
print(event.position);
},
child: new Draggable(
key: ObjectKey('card3'),
child: new Card(
color: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Container(
),
),
feedback: new Card(
color: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Container(
width: box.size.width,
height: box.size.height,
),
),
childWhenDragging: Container(),
),
),
],
);
}),
),
);
}
}
Please use LayoutBuilder
to construct the Draggable
. It's builder function receives a constrains param with which you can adjust the size of the feedback. This is much better because you cannot always have a GlobalKey
if you have a list with dynamic data.
Example:
LayoutBuilder(
builder: (context, constraints) => Draggable(
child: Container(...),
feedback: Container (
width: constraints.maxWidth,
)
),
);
You can determine a Widget's size by using its GlobalKey. I posted this comment on GitHub for a ListView, but I think you will be able to use the same example for a Stack.
ListView.builder(
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
GlobalKey myKey = GlobalKey();
return Draggable(
child: ListTile(
key: myKey,
title: Text("Tile #$index"),
),
childWhenDragging: Opacity(
opacity: 0.2,
child: ListTile(
title: Text("Tile #$index"),
),
),
feedback: FeedbackWidget(
dragChildKey: myKey,
child: ListTile(
title: Text("Tile #$index"),
),
),
);
}
)
class FeedbackWidget extends StatelessWidget{
final GlobalKey dragChildKey;
final Widget child;
const FeedbackWidget({Key key, this.dragChildKey, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
//Determine the size of the original widget
final RenderBox renderBoxRed = dragChildKey.currentContext.findRenderObject();
final size = renderBoxRed.size;
return Container(
width: size.width,
height: size.height,
child: Material(
child: child,
),
);
}
}
You can also look at this Medium article
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With