how to make a container draggable in horizontal direction in flutter

Viewed 342

How do I get a draggable container like this, which when reaches a certain point gets vanished and a function could be called at that time. Also, the visibility of text is also decreasing and arrow icon is rotating according to the length. How can I achieve this functionality?

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

I have written a code, and I can add visibility widget for same. But, how to constraint it and what is the best way of doing it? Please help me out -

import 'package:flutter/material.dart';

class SwipeButton extends StatefulWidget {
  const SwipeButton({Key? key}) : super(key: key);

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

class _SwipeButtonState extends State<SwipeButton> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          color: Colors.orange,
          width: MediaQuery.of(context).size.width * 0.9,
          height: 50,
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 8.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Draggable<int>(
                  data: 10,
                  feedback: Container(
                    height: 20.0,
                    width: 20.0,
                    color: Colors.white,
                    child: const Center(
                      child: Icon(
                        Icons.arrow_forward,
                        size: 12,
                      ),
                    ),
                  ),
                  axis: Axis.horizontal,
                  childWhenDragging: Container(
                    height: 20.0,
                    width: 20.0,
                    color: Colors.orange,
                    child: const Center(
                      child: Text(''),
                    ),
                  ),
                  child: Container(
                    height: 20.0,
                    width: 20.0,
                    color: Colors.white,
                    child: const Center(
                      child: Icon(
                        Icons.arrow_forward,
                        size: 12,
                      ),
                    ),
                  ),
                ),
                DragTarget<int>(
                  builder: (
                    BuildContext context,
                    List<dynamic> accepted,
                    List<dynamic> rejected,
                  ) {
                    return Container(
                      height: 20.0,
                      width: 20.0,
                      color: Colors.orange,
                      child: const Center(
                        child: Text(''),
                      ),
                    );
                  },
                  onAccept: (int data) {
                    setState(() {
                      print(data);
                    });
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
1 Answers

For the arrow, we can use Transform.rotate.

Transform.rotate(
  angle: deg2rad(-(180 + 20) * (posX / maxWidth)), // 20 comes from icon size
  child: const Icon(
    Icons.arrow_forward,
    size: 12,
  ),
),

I'm not sure why onDragUpdate is not updating the UI, you can get current position of drag from that, I store it on posX.

I am using GestureDetector for test case, apply the same logic you will get the result.

Run on dartPad

class SwipeButton extends StatefulWidget {
  const SwipeButton({Key? key}) : super(key: key);

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

class _SwipeButtonState extends State<SwipeButton> {
  double deg2rad(double deg) => deg * pi / 180;
  double posX = 0.0;

  @override
  Widget build(BuildContext context) {
    final maxWidth = MediaQuery.of(context).size.width * 0.9;

    return Scaffold(
      body: Center(
        child: Container(
          color: Colors.orange,
          width: maxWidth * 0.9,
          height: 50,
          child: Stack(
            alignment: Alignment.center,
            children: [
              AnimatedPositioned(
                duration: const Duration(milliseconds: 100),
                left: posX,
                key: const ValueKey("item 1"),
                child: Container(
                  height: 20.0,
                  width: 20.0,
                  color: Colors.white,
                  alignment: Alignment.center,
                  child: Transform.rotate(
                    angle: deg2rad(-(180 + 20) * (posX / maxWidth)),
                    child: const Icon(
                      Icons.arrow_forward,
                      size: 12,
                    ),
                  ),
                ),
              ),
              GestureDetector(
                onPanEnd: (details) {
                  setState(() {
                    posX = 0;
                  });
                },
                onPanUpdate: (details) {
                  setState(() {
                    posX = details.localPosition.dx;
                  });

                  if (posX / maxWidth > .95) {
                    debugPrint("on success drag");
                  }
                },
              )
            ],
          ),
        ),
      ),
    );
  }
}

Related