Creating Resizable View that resizes when pinch or drag from corners and sides in FLUTTER

9,504

Solution 1

Updated

I've made a simple prototype to show the idea.

  1. Draw size handlers and a container;
  2. Use GestureDetector to detect dragging;
  3. Refresh the main container size and coordinates.

enter image description here

    import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Text Overflow Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: Demo(),
      ),
    );
  }
}

class Demo extends StatefulWidget {
  @override
  _DemoState createState() => _DemoState();
}

class _DemoState extends State<Demo> {
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(60),
      child: ResizebleWidget(
        child: Text(
'''I've just did simple prototype to show main idea.
  1. Draw size handlers with container;
  2. Use GestureDetector to get new variables of sizes
  3. Refresh the main container size.''',
        ),
      ),
    );
  }
}

class ResizebleWidget extends StatefulWidget {
  ResizebleWidget({this.child});

  final Widget child;
  @override
  _ResizebleWidgetState createState() => _ResizebleWidgetState();
}

const ballDiameter = 30.0;

class _ResizebleWidgetState extends State<ResizebleWidget> {
  double height = 400;
  double width = 200;

  double top = 0;
  double left = 0;

  void onDrag(double dx, double dy) {
    var newHeight = height + dy;
    var newWidth = width + dx;

    setState(() {
      height = newHeight > 0 ? newHeight : 0;
      width = newWidth > 0 ? newWidth : 0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Positioned(
          top: top,
          left: left,
          child: Container(
            height: height,
            width: width,
            color: Colors.red[100],
            child: widget.child,
          ),
        ),
        // top left
        Positioned(
          top: top - ballDiameter / 2,
          left: left - ballDiameter / 2,
          child: ManipulatingBall(
            onDrag: (dx, dy) {
              var mid = (dx + dy) / 2;
              var newHeight = height - 2 * mid;
              var newWidth = width - 2 * mid;

              setState(() {
                height = newHeight > 0 ? newHeight : 0;
                width = newWidth > 0 ? newWidth : 0;
                top = top + mid;
                left = left + mid;
              });
            },
          ),
        ),
        // top middle
        Positioned(
          top: top - ballDiameter / 2,
          left: left + width / 2 - ballDiameter / 2,
          child: ManipulatingBall(
            onDrag: (dx, dy) {
              var newHeight = height - dy;

              setState(() {
                height = newHeight > 0 ? newHeight : 0;
                top = top + dy;
              });
            },
          ),
        ),
        // top right
        Positioned(
          top: top - ballDiameter / 2,
          left: left + width - ballDiameter / 2,
          child: ManipulatingBall(
            onDrag: (dx, dy) {
              var mid = (dx + (dy * -1)) / 2;

              var newHeight = height + 2 * mid;
              var newWidth = width + 2 * mid;

              setState(() {
                height = newHeight > 0 ? newHeight : 0;
                width = newWidth > 0 ? newWidth : 0;
                top = top - mid;
                left = left - mid;
              });
            },
          ),
        ),
        // center right
        Positioned(
          top: top + height / 2 - ballDiameter / 2,
          left: left + width - ballDiameter / 2,
          child: ManipulatingBall(
            onDrag: (dx, dy) {
              var newWidth = width + dx;

              setState(() {
                width = newWidth > 0 ? newWidth : 0;
              });
            },
          ),
        ),
        // bottom right
        Positioned(
          top: top + height - ballDiameter / 2,
          left: left + width - ballDiameter / 2,
          child: ManipulatingBall(
            onDrag: (dx, dy) {
              var mid = (dx + dy) / 2;

              var newHeight = height + 2 * mid;
              var newWidth = width + 2 * mid;

              setState(() {
                height = newHeight > 0 ? newHeight : 0;
                width = newWidth > 0 ? newWidth : 0;
                top = top - mid;
                left = left - mid;
              });
            },
          ),
        ),
        // bottom center
        Positioned(
          top: top + height - ballDiameter / 2,
          left: left + width / 2 - ballDiameter / 2,
          child: ManipulatingBall(
            onDrag: (dx, dy) {
              var newHeight = height + dy;

              setState(() {
                height = newHeight > 0 ? newHeight : 0;
              });
            },
          ),
        ),
        // bottom left
        Positioned(
          top: top + height - ballDiameter / 2,
          left: left - ballDiameter / 2,
          child: ManipulatingBall(
            onDrag: (dx, dy) {
              var mid = ((dx * -1) + dy) / 2;

              var newHeight = height + 2 * mid;
              var newWidth = width + 2 * mid;

              setState(() {
                height = newHeight > 0 ? newHeight : 0;
                width = newWidth > 0 ? newWidth : 0;
                top = top - mid;
                left = left - mid;
              });
            },
          ),
        ),
        //left center
        Positioned(
          top: top + height / 2 - ballDiameter / 2,
          left: left - ballDiameter / 2,
          child: ManipulatingBall(
            onDrag: (dx, dy) {
              var newWidth = width - dx;

              setState(() {
                width = newWidth > 0 ? newWidth : 0;
                left = left + dx;
              });
            },
          ),
        ),
        // center center
        Positioned(
          top: top + height / 2 - ballDiameter / 2,
          left: left + width / 2 - ballDiameter / 2,
          child: ManipulatingBall(
            onDrag: (dx, dy) {
              setState(() {
                top = top + dy;
                left = left + dx;
              });
            },
          ),
        ),
      ],
    );
  }
}

class ManipulatingBall extends StatefulWidget {
  ManipulatingBall({Key key, this.onDrag});

  final Function onDrag;

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

class _ManipulatingBallState extends State<ManipulatingBall> {
  double initX;
  double initY;

  _handleDrag(details) {
    setState(() {
      initX = details.globalPosition.dx;
      initY = details.globalPosition.dy;
    });
  }

  _handleUpdate(details) {
    var dx = details.globalPosition.dx - initX;
    var dy = details.globalPosition.dy - initY;
    initX = details.globalPosition.dx;
    initY = details.globalPosition.dy;
    widget.onDrag(dx, dy);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanStart: _handleDrag,
      onPanUpdate: _handleUpdate,
      child: Container(
        width: ballDiameter,
        height: ballDiameter,
        decoration: BoxDecoration(
          color: Colors.blue.withOpacity(0.5),
          shape: BoxShape.circle,
        ),
      ),
    );
  }
}

Solution 2

I did a discrete version (ie snaps every 50 units) of the code above if it helps anyone:

    import 'package:flutter/material.dart';
    
    class DiscreteResizableComponent extends StatefulWidget {
      const DiscreteResizableComponent({Key key, this.child}):super(key:key);
    
      final Widget child;
      @override
      _ResizebleWidgetState createState() => _ResizebleWidgetState();
    }
    
    const ballDiameter = 30.0;
    const discreteStepSize = 50;
    
    class _ResizebleWidgetState extends State<DiscreteResizableComponent> {
      double height = 400;
      double width = 200;
    
      double top = 0;
      double left = 0;
    
      double cumulativeDy=0;
      double cumulativeDx=0;
      double cumulativeMid = 0;
    
      void onDrag(double dx, double dy) {
        var newHeight = height + dy;
        var newWidth = width + dx;
    
        setState(() {
          height = newHeight > 0 ? newHeight : 0;
          width = newWidth > 0 ? newWidth : 0;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          children: <Widget>[
            Positioned(
              top: top,
              left: left,
              child: Container(
                height: height,
                width: width,
                color: Colors.red[100],
                child: widget.child,
              ),
            ),
            // top left
            Positioned(
              top: top - ballDiameter / 2,
              left: left - ballDiameter / 2,
              child: ManipulatingBall(
                onDrag: (dx, dy) {
                  var mid = (dx + dy) / 2;
                  cumulativeMid -= 2*mid;
                  if(cumulativeMid>=discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height+discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      var newWidth = width +discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeMid=0;
                    });
                  }
                  else if(cumulativeMid<=-discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height - discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      var newWidth = width - discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeMid=0;
                    });
                  }
                },
              ),
            ),
            // top middle
            Positioned(
              top: top - ballDiameter / 2,
              left: left + width / 2 - ballDiameter / 2,
              child: ManipulatingBall(
                onDrag: (dx, dy) {
                  cumulativeDy -= dy;
                  if(cumulativeDy>=discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height+discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      cumulativeDy=0;
                    });
                  }
                  else if(cumulativeDy<=-discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height - discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      cumulativeDy=0;
                    });
                  }
                },
              ),
            ),
            // top right
            Positioned(
              top: top - ballDiameter / 2,
              left: left + width - ballDiameter / 2,
              child: ManipulatingBall(
                onDrag: (dx, dy) {
                  var mid = (dx + (dy * -1)) / 2;
                  cumulativeMid += 2*mid;
                  if(cumulativeMid>=discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height+discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      var newWidth = width +discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeMid=0;
                    });
                  }
                  else if(cumulativeMid<=-discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height - discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      var newWidth = width - discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeMid=0;
                    });
                  }
                },
              ),
            ),
            // center right
            Positioned(
              top: top + height / 2 - ballDiameter / 2,
              left: left + width - ballDiameter / 2,
              child: ManipulatingBall(
                onDrag: (dx, dy) {
                  cumulativeDx += dx;
    
                  if(cumulativeDx>=discreteStepSize)
                  {
                    setState(() {
                      var newWidth = width+discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeDx=0;
                    });
                  }
                  else if(cumulativeDx<=-discreteStepSize)
                  {
                    setState(() {
                      var newWidth = width-discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeDx=0;
                    });
                  }
                },
              ),
            ),
            // bottom right
            Positioned(
              top: top + height - ballDiameter / 2,
              left: left + width - ballDiameter / 2,
              child: ManipulatingBall(
                onDrag: (dx, dy) {
                  var mid = (dx + dy) / 2;
    
                  cumulativeMid += 2*mid;
                  if(cumulativeMid>=discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height+discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      var newWidth = width +discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeMid=0;
                    });
                  }
                  else if(cumulativeMid<=-discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height - discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      var newWidth = width - discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeMid=0;
                    });
                  }
                },
              ),
            ),
            // bottom center
            Positioned(
              top: top + height - ballDiameter / 2,
              left: left + width / 2 - ballDiameter / 2,
              child: ManipulatingBall(
                onDrag: (dx, dy) {
                  cumulativeDy += dy;
    
                  if(cumulativeDy>=discreteStepSize)
                    {
                      setState(() {
                        var newHeight = height+discreteStepSize;
                        height = newHeight > 0 ? newHeight : 0;
                        cumulativeDy=0;
                      });
                    }
                  else if(cumulativeDy<=-discreteStepSize)
                    {
                      setState(() {
                        var newHeight = height-discreteStepSize;
                        height = newHeight > 0 ? newHeight : 0;
                        cumulativeDy=0;
                      });
                    }
                },
              ),
            ),
            // bottom left
            Positioned(
              top: top + height - ballDiameter / 2,
              left: left - ballDiameter / 2,
              child: ManipulatingBall(
                onDrag: (dx, dy) {
                  var mid = ((dx * -1) + dy) / 2;
    
                  cumulativeMid += 2*mid;
                  if(cumulativeMid>=discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height+discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      var newWidth = width +discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeMid=0;
                    });
                  }
                  else if(cumulativeMid<=-discreteStepSize)
                  {
                    setState(() {
                      var newHeight = height - discreteStepSize;
                      height = newHeight > 0 ? newHeight : 0;
                      var newWidth = width - discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeMid=0;
                    });
                  }
                },
              ),
            ),
            //left center
            Positioned(
              top: top + height / 2 - ballDiameter / 2,
              left: left - ballDiameter / 2,
              child: ManipulatingBall(
                onDrag: (dx, dy) {
                  cumulativeDx -= dx;
    
                  if(cumulativeDx>=discreteStepSize)
                  {
                    setState(() {
                      var newWidth = width+discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeDx=0;
                    });
                  }
                  else if(cumulativeDx<=-discreteStepSize)
                  {
                    setState(() {
                      var newWidth = width-discreteStepSize;
                      width = newWidth > 0 ? newWidth : 0;
                      cumulativeDx=0;
                    });
                  }
                },
              ),
            ),
          ],
        );
      }
    }
    
    class ManipulatingBall extends StatefulWidget {
      ManipulatingBall({Key key, this.onDrag});
    
      final Function onDrag;
    
      @override
      _ManipulatingBallState createState() => _ManipulatingBallState();
    }
    
    class _ManipulatingBallState extends State<ManipulatingBall> {
      double initX;
      double initY;
    
      _handleDrag(details) {
        setState(() {
          initX = details.globalPosition.dx;
          initY = details.globalPosition.dy;
        });
      }
    
      _handleUpdate(details) {
        var dx = details.globalPosition.dx - initX;
        var dy = details.globalPosition.dy - initY;
        initX = details.globalPosition.dx;
        initY = details.globalPosition.dy;
        widget.onDrag(dx, dy);
      }
    
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          onPanStart: _handleDrag,
          onPanUpdate: _handleUpdate,
          child: Container(
            width: ballDiameter,
            height: ballDiameter,
            decoration: BoxDecoration(
              color: Colors.blue.withOpacity(0.5),
              shape: BoxShape.circle,
            ),
          ),
        );
      }
    }
Share:
9,504
jazzbpn
Author by

jazzbpn

With 6+ years of experience, I have developed many iOS/android applications in different context, professional and oldest passion for computer programming began very early in my life. I've learned the social environment is as important as logic aspects of the developing approach then I appreciate very much to get in touch with positive and eager colleagues that involve me in new and exciting challenges. This is why I still want to get involved in new opportunities to improve my skillness.

Updated on December 19, 2022

Comments

  • jazzbpn
    jazzbpn over 1 year

    enter image description here

    I am currently working on a ScreenView with features like draggable and resizable views with corners and sides like in the image above. The problem I have now is that I want to resize the view by touch gestures in the corners. Therefore, I thought of a Point which I add to a view on selection, which can be dragged to resize the selected view. Answer updated!!

    Resizable-Widget ReactNative Demo: React Native PLUGIN example

    Modified Workable Example:

      import 'package:flutter/material.dart';
    
      class ResizeWidget extends StatefulWidget {
        @override
        _ResizeWidgetState createState() => _ResizeWidgetState();
      }
    
      class _ResizeWidgetState extends State<ResizeWidget> {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            home: Scaffold(
              backgroundColor: Colors.black,
              body: Container(
                // padding: EdgeInsets.only(top: 50),
                child: ResizebleWidget(
                  child: Container(
                    padding: EdgeInsets.all(10),
                    child: Text(
                      'Waao!! you can really dance.',
                      style: TextStyle(
                          color: Colors.white,
                          fontStyle: FontStyle.italic,
                          fontSize: 18),
                    ),
                  ),
                ),
              ),
            ),
          );
        }
      }
    
      class ResizebleWidget extends StatefulWidget {
        ResizebleWidget({this.child});
    
        final Widget child;
        @override
        _ResizebleWidgetState createState() => _ResizebleWidgetState();
      }
    
      const ballDiameter = 10.0;
    
      class _ResizebleWidgetState extends State<ResizebleWidget> {
        double height = 100;
        double width = 200;
        bool isCorner = false;
    
        double top = 0;
        double left = 0;
    
        @override
        Widget build(BuildContext context) {
          return Stack(
            children: <Widget>[
              Positioned(
                top: top,
                left: left,
                child: Container(
                  height: height,
                  width: width,
    
                  decoration: BoxDecoration(
                    color: Colors.blueGrey,
                    border: Border.all(
                      width: 2,
                      color: Colors.white70,
                    ),
                    borderRadius: BorderRadius.circular(0.0),
                  ),
    
                  // need tp check if draggable is done from corner or sides
                  child: isCorner
                      ? FittedBox(
                          child: widget.child,
                        )
                      : Center(
                          child: widget.child,
                        ),
                ),
              ),
              // top left
              Positioned(
                top: top - ballDiameter / 2,
                left: left - ballDiameter / 2,
                child: ManipulatingBall(
                  onDrag: (dx, dy) {
                    var mid = (dx + dy) / 2;
                    var newHeight = height - 2 * mid;
                    var newWidth = width - 2 * mid;
    
                    setState(() {
                      isCorner = true;
                      height = newHeight > 0 ? newHeight : 0;
                      width = newWidth > 0 ? newWidth : 0;
                      top = top + mid;
                      left = left + mid;
                    });
                  },
                  handlerWidget: HandlerWidget.VERTICAL,
                ),
              ),
              // top middle
              Positioned(
                top: top - ballDiameter / 2,
                left: left + width / 2 - ballDiameter / 2,
                child: ManipulatingBall(
                  onDrag: (dx, dy) {
                    var newHeight = height - dy;
    
                    setState(() {
                      isCorner = false;
    
                      height = newHeight > 0 ? newHeight : 0;
                      top = top + dy;
                    });
                  },
                  handlerWidget: HandlerWidget.HORIZONTAL,
                ),
              ),
              // top right
              Positioned(
                top: top - ballDiameter / 2,
                left: left + width - ballDiameter / 2,
                child: ManipulatingBall(
                  onDrag: (dx, dy) {
                    var mid = (dx + (dy * -1)) / 2;
    
                    var newHeight = height + 2 * mid;
                    var newWidth = width + 2 * mid;
    
                    setState(() {
                      isCorner = true;
                      height = newHeight > 0 ? newHeight : 0;
                      width = newWidth > 0 ? newWidth : 0;
                      top = top - mid;
                      left = left - mid;
                    });
                  },
                  handlerWidget: HandlerWidget.VERTICAL,
                ),
              ),
              // center right
              Positioned(
                top: top + height / 2 - ballDiameter / 2,
                left: left + width - ballDiameter / 2,
                child: ManipulatingBall(
                  onDrag: (dx, dy) {
                    var newWidth = width + dx;
    
                    setState(() {
                      isCorner = false;
    
                      width = newWidth > 0 ? newWidth : 0;
                    });
                  },
                  handlerWidget: HandlerWidget.HORIZONTAL,
                ),
              ),
              // bottom right
              Positioned(
                top: top + height - ballDiameter / 2,
                left: left + width - ballDiameter / 2,
                child: ManipulatingBall(
                  onDrag: (dx, dy) {
                    var mid = (dx + dy) / 2;
    
                    var newHeight = height + 2 * mid;
                    var newWidth = width + 2 * mid;
    
                    setState(() {
                      isCorner = true;
    
                      height = newHeight > 0 ? newHeight : 0;
                      width = newWidth > 0 ? newWidth : 0;
                      top = top - mid;
                      left = left - mid;
                    });
                  },
                  handlerWidget: HandlerWidget.VERTICAL,
                ),
              ),
              // bottom center
              Positioned(
                top: top + height - ballDiameter / 2,
                left: left + width / 2 - ballDiameter / 2,
                child: ManipulatingBall(
                  onDrag: (dx, dy) {
                    var newHeight = height + dy;
    
                    setState(() {
                      isCorner = false;
    
                      height = newHeight > 0 ? newHeight : 0;
                    });
                  },
                  handlerWidget: HandlerWidget.HORIZONTAL,
                ),
              ),
              // bottom left
              Positioned(
                top: top + height - ballDiameter / 2,
                left: left - ballDiameter / 2,
                child: ManipulatingBall(
                  onDrag: (dx, dy) {
                    var mid = ((dx * -1) + dy) / 2;
    
                    var newHeight = height + 2 * mid;
                    var newWidth = width + 2 * mid;
    
                    setState(() {
                      isCorner = true;
    
                      height = newHeight > 0 ? newHeight : 0;
                      width = newWidth > 0 ? newWidth : 0;
                      top = top - mid;
                      left = left - mid;
                    });
                  },
                  handlerWidget: HandlerWidget.VERTICAL,
                ),
              ),
              //left center
              Positioned(
                top: top + height / 2 - ballDiameter / 2,
                left: left - ballDiameter / 2,
                child: ManipulatingBall(
                  onDrag: (dx, dy) {
                    var newWidth = width - dx;
    
                    setState(() {
                      isCorner = false;
    
                      width = newWidth > 0 ? newWidth : 0;
                      left = left + dx;
                    });
                  },
                  handlerWidget: HandlerWidget.HORIZONTAL,
                ),
              ),
              // center center
              Positioned(
                top: top + height / 2 - ballDiameter / 2,
                left: left + width / 2 - ballDiameter / 2,
                child: ManipulatingBall(
                  onDrag: (dx, dy) {
                    setState(() {
                      isCorner = false;
    
                      top = top + dy;
                      left = left + dx;
                    });
                  },
                  handlerWidget: HandlerWidget.VERTICAL,
                ),
              ),
            ],
          );
        }
      }
    
      class ManipulatingBall extends StatefulWidget {
        ManipulatingBall({Key key, this.onDrag, this.handlerWidget});
    
        final Function onDrag;
        final HandlerWidget handlerWidget;
    
        @override
        _ManipulatingBallState createState() => _ManipulatingBallState();
      }
    
      enum HandlerWidget { HORIZONTAL, VERTICAL }
    
      class _ManipulatingBallState extends State<ManipulatingBall> {
        double initX;
        double initY;
    
        _handleDrag(details) {
          setState(() {
            initX = details.globalPosition.dx;
            initY = details.globalPosition.dy;
          });
        }
    
        _handleUpdate(details) {
          var dx = details.globalPosition.dx - initX;
          var dy = details.globalPosition.dy - initY;
          initX = details.globalPosition.dx;
          initY = details.globalPosition.dy;
          widget.onDrag(dx, dy);
        }
    
        @override
        Widget build(BuildContext context) {
          return GestureDetector(
            onPanStart: _handleDrag,
            onPanUpdate: _handleUpdate,
            child: Container(
              width: ballDiameter,
              height: ballDiameter,
              decoration: BoxDecoration(
                color: Colors.white,
                shape: this.widget.handlerWidget == HandlerWidget.VERTICAL
                    ? BoxShape.circle
                    : BoxShape.rectangle,
              ),
            ),
          );
        }
      }
    

    Output:

    enter image description here

  • jazzbpn
    jazzbpn about 4 years
    Thanks for the example. But the required result should have a feature like double tap zoom, pinch to zoom and zoom-in/out from sides and corner as well.
  • Kherel
    Kherel about 4 years
    Implementing a whole library would take more time. But there are existing libraries for pinch zoom. You can find it pub.com.
  • jazzbpn
    jazzbpn about 4 years
    Ok. But, How to make the borders like in the react-native plugin? ManipulatingBall on four-sides and in middle-left and middle-right of the widget(like in the react-native plugin).
  • Kherel
    Kherel about 4 years
    yes, nine handlers. All of them has their own drag handlers. Corner handlers and a center handler react on x and y change. Side handlers react on x or y change. Main container has size and coordiante. Left and and top size handlers change coordinate and size. Right and bottom size handlers change size. The center handler change only coordinate.
  • jazzbpn
    jazzbpn about 4 years
    When dragging from the four-corners both height and width should increase/decrease in same ratio. It should behave like zoom-in/out. How to achieve that?
  • Kherel
    Kherel about 4 years
  • jazzbpn
    jazzbpn about 4 years
    Sure I will upvote. But before that do you mind helping me with one more issue? Please check this video: drive.google.com/file/d/1IXi6D6P4hrD7qpPYHnwvABdQYlklqgL6/… 1. AutoMultiline TextView when dragging from sides (DONE) 2. Zoomable feature for Text or EditText when dragging from corner( Not-Done). The output should be like when the user zoom-in/out the widget will zoom-in/out without being in multiline. Could you please help me with this last issue? Thank you!!
  • Kherel
    Kherel about 4 years
  • AgentRed
    AgentRed over 2 years
    @Kherel I've tried your code, but I have a problem when I use transform.rotate and rotated (for example) 45 degrees it doesn't behave the same way. is it because it now have different left and top position?