Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draggable feedback same size as child

Tags:

flutter

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(),
                ),
              ),
            ],
          );
        }),
      ),
    );
  }
}
like image 480
Adam Avatar asked Nov 06 '22 15:11

Adam


1 Answers

UPDATE

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,
    )
  ),
);

Initial post

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

like image 162
Jandries Avatar answered Dec 05 '22 21:12

Jandries