5

I want to create a resizable container which can be resized by user using horizontal drag.

This Gif can explain the requirement:

enter image description here

I tried GestureDetector.horizontal drag but the results are way off:

Container(
        color: primary,
        width: size.width,
        height: 40,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            GestureDetector(
              onHorizontalDragUpdate: (details) {
                final double newWidth;
                if (details.delta.dx > 0) {
                  // movement in positive direction
                  final newWidth = size.width + 1;

                  print(newWidth);
                  final updatedSize = Size(newWidth, size.height);

                  setState(() {
                    size = updatedSize;
                  });
                } else {
                  // movement in negative direction
                  final newWidth = math.max(size.width - 1, 5).toDouble();
                  print(newWidth);
                  final updatedSize = Size(newWidth, size.height);

                  setState(() {
                    size = updatedSize;
                  });
                }
              },
              child: const Icon(
                Icons.navigate_before_rounded,
                color: Colors.white,
              ),
            ),
            GestureDetector(
              onHorizontalDragUpdate: (det) {
                if (det.delta.dx > 1) {
                  var newWidth = size.width + 1;

                  final updatedSize = Size(newWidth, size.height);

                  setState(() {
                    size = updatedSize;
                  });
                } else {
                  var newWidth = size.width - 1;
                  newWidth = math.max(newWidth, 10);
                  final updatedSize = Size(newWidth, size.height);

                  setState(() {
                    size = updatedSize;
                  });
                }

                
              },
              child: const Icon(
                Icons.navigate_next_rounded,
                color: Colors.white,
              ),
            ),
          ],
        ),
      ),

enter image description here

I am looking for a way to get size change of one side using drag, also the width should decrease or increase on the basis of dragging direction and if possible the whole container can be moved as well.

Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
Raj Dhakad
  • 852
  • 2
  • 17
  • 39
  • 1
    Check this: https://stackoverflow.com/questions/60924384/creating-resizable-view-that-resizes-when-pinch-or-drag-from-corners-and-sides-i – Rohit Suthar Jun 16 '22 at 06:06

2 Answers2

7

You can use Stack with Positioned widget to handle container sizing and to drag the full container I am using transform.

enter image description here

Run on dartPad

You can play with this widget.

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

  @override
  State<FContainer> createState() => _FContainerState();
}

class _FContainerState extends State<FContainer> {

  ///initial position
  double leftPos = 33;
  double rightPos = 33;
  double transformX = 0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: LayoutBuilder(
        builder: (context, constraints) => Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              transform: Matrix4.translationValues(transformX, 0, 0),
              height: 60,
              width: constraints.maxWidth,
              child: Stack(
                children: [
                  Positioned(
                    top: 0,
                    bottom: 0,
                    left: leftPos,
                    right: rightPos,
                    child: Row(
                      children: [
                        GestureDetector(
                          onTap: () {},
                          onHorizontalDragUpdate: (details) {
                            leftPos = details.globalPosition.dx;
                            setState(() {});
                            debugPrint(leftPos.toString());
                          },
                          child: Container(
                            height: 60,
                            color: Colors.purple,
                            child: const Icon(
                              Icons.navigate_next_rounded,
                              color: Colors.black,
                            ),
                          ),
                        ),
                        Expanded(
                          child: GestureDetector(
                            onTap: () {},
                            onHorizontalDragUpdate: (details) {
                              final midPos = details.delta;
                              transformX += midPos.dx;
                              setState(() {});
                              debugPrint(midPos.toString());
                            },
                            child: Container(
                              color: Colors.purple,
                            ),
                          ),
                        ),
                        GestureDetector(
                          onTap: () {},
                          onHorizontalDragUpdate: (details) {
                            rightPos = constraints.maxWidth -
                                details.globalPosition.dx;
                            setState(() {});
                            debugPrint(rightPos.toString());
                          },
                          child: Container(
                            height: 60,
                            color: Colors.purple,
                            child: const Icon(
                              Icons.navigate_before_rounded,
                              color: Colors.black,
                            ),
                          ),
                        ),
                      ],
                    ),
                  )
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

You can wrap with if condition to avoid getting out of the screen.

Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
1

Here is an updated version of @Yeasin Sheikh´s answer that takes care of some bugs and avoids both going outside the window and crossing over itself.

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

  @override
  State<inputBox> createState() => _inputBoxState();
}

class _inputBoxState extends State<inputBox> {
  ///initial position or size of the bar
  double leftPos = 30;
  double rightPos = 30;
  double transformX = 0;
  double barHeight = 30;

  double _expandedWidth = 0.0; // keep track of the middle bar width

  @override
  Widget build(BuildContext context) {
    return Center(
      child: LayoutBuilder(
        builder: (context, constraints) => Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              transform: Matrix4.translationValues(0, 0, 0),
              height: barHeight,
              width: constraints.maxWidth,
              child: Stack(
                children: [
                  Positioned(
                    top: 0,
                    bottom: 0,
                    left: leftPos,
                    right: rightPos,
                    child: Row(
                      children: [
                        GestureDetector(
                          onTap: () {},
                          onHorizontalDragUpdate: (DragUpdateDetails details) {
                            final moveDelta = details.delta;

                            setState(() {
                              // Don't let the user pass outside the window or through the right dragbox
                              if (leftPos > 0 && _expandedWidth > 10) {
                                leftPos += moveDelta.dx;
                              } else if (leftPos < 0) {
                                // Do something when leftPos is less than zero
                                leftPos = 0.01;
                              } else if (_expandedWidth < 10) {
                                // Do something when _expandedWidth is less than
                                leftPos -= 20;
                              }
                            });
                          },
                          child: Container(
                            height: barHeight,
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.only(
                                  topRight: Radius.circular(0),
                                  bottomRight: Radius.circular(0),
                                  topLeft: Radius.circular(barHeight * 0.315),
                                  bottomLeft:
                                      Radius.circular(barHeight * 0.315)),
                              color: Color.fromARGB(255, 119, 176, 39),
                            ),
                            child: const Icon(
                              Icons.navigate_next_rounded,
                              color: Colors.black,
                            ),
                          ),
                        ),
                        Expanded(
                          child: LayoutBuilder(
                            builder: (BuildContext context,
                                BoxConstraints constraints) {
                              double containerWidth = constraints.maxWidth;
                              _expandedWidth =
                                  containerWidth; // store the current width in a state variable
                              return GestureDetector(
                                onTap: () {},
                                onHorizontalDragUpdate:
                                    (DragUpdateDetails details) {
                                  final moveDelta = details.delta;

                                  setState(() {
                                    if (leftPos > 0 && rightPos > 0) {
                                      leftPos += moveDelta.dx;
                                      rightPos -= moveDelta.dx;
                                    } else if (leftPos < 0) {
                                      // Do something when leftPos is less than zero
                                      leftPos +=
                                          moveDelta.dx + 10; // move back in
                                      rightPos -=
                                          moveDelta.dx + 10; // move back in
                                    } else if (rightPos < 0) {
                                      // Do something when rightPos is less than zero
                                      leftPos +=
                                          moveDelta.dx - 10; // move back in
                                      rightPos -=
                                          moveDelta.dx - 10; // move back in
                                    }
                                  });
                                },
                                child: Container(
                                  color: Color.fromARGB(255, 119, 176, 39),
                                  width: containerWidth,
                                ),
                              );
                            },
                          ),
                        ),
                        GestureDetector(
                            onTap: () {},
                            onHorizontalDragUpdate:
                                (DragUpdateDetails details) {
                              final moveDelta = details.delta;
                              setState(() {

                                // Don't let the user pass outside the window or through the left dragbox
                                if (rightPos > 0 && _expandedWidth > 10) {
                                  rightPos -= moveDelta.dx;
                                } else if (rightPos < 0) {
                                  // Do something when rightPos is less than zero
                                  rightPos = 0.01;
                                } else if (_expandedWidth < 10) {
                                  // Do something when _expandedWidth is less than
                                  rightPos -= 20;
                                }
                              });
                            },
                            child: Container(
                                decoration: BoxDecoration(
                                  borderRadius: BorderRadius.only(
                                      topRight:
                                          Radius.circular(barHeight * 0.315),
                                      bottomRight:
                                          Radius.circular(barHeight * 0.315),
                                      topLeft: Radius.circular(0),
                                      bottomLeft: Radius.circular(0)),
                                  color: Color.fromARGB(255, 119, 176, 39),
                                ),
                                height: barHeight,
                                child: const Icon(
                                  Icons.navigate_before_rounded,
                                  color: Colors.black,
                                ))),
                      ],
                    ),
                  )
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}