flutter - 创建可调整大小的 View ,当在 FLUTTER 中从角落和侧面捏或拖动时调整大小

标签 flutter resize flutter-layout image-resizing window-resize

enter image description here

我目前正在开发具有可拖动和可调整大小的 View 等功能的 ScreenView,如上图所示。我现在遇到的问题是我想通过角落的触摸手势来调整 View 的大小。因此,我想到了一个点,我将它添加到选择 View 中,可以拖动它来调整选定 View 的大小。答案更新!!

可调整大小的小部件 ReactNative 演示: React Native PLUGIN 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,
          ),
        ),
      );
    }
  }

输出:

enter image description here

最佳答案

更新

我制作了一个简单的原型(prototype)来展示这个想法。

  • 绘制尺寸处理程序和容器;
  • 使用 GestureDetector 检测拖动;
  • 刷新主容器大小和坐标。

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

    关于flutter - 创建可调整大小的 View ,当在 FLUTTER 中从角落和侧面捏或拖动时调整大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60924384/

    相关文章:

    Flutter AOT 与 JIT

    flutter - 如何将底部工作表位置设置为顶部

    flutter - 如何在 flutter 中像选中的芯片一样取消选择(未选择)的芯片?

    python - 使用PIL查看tif文件,调整大小时质量较差

    flutter - 带有动画提示/标签的文本字段

    firebase - 为ListView异步构建窗口小部件的 flutter 问题

    gridview - 调整 MFC 网格控件的大小以适应对话框?

    java - 如何在 Java Swing 中动态控制自动调整大小的组件

    flutter - 在Flutter中更新模态类属性时,UI不更新

    flutter - 在 Flutter 中创建对齐文本的网格/表格