Create a resizable view in flutter

荒凉一梦 提交于 2021-01-29 09:42:03

问题


I am creating a resizable view for an image. The code is as follows:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: SafeArea(
          child: ImageManager(),
        ),
      ),
    );
  }
}

final ballRadius = 7.5;

class ImageManager extends StatefulWidget {
  @override
  _ImageManagerState createState() => _ImageManagerState();
}

class _ImageManagerState extends State<ImageManager> {
  double _x = 0;
  double _y = 0;

  double _height = 200;
  double _width = 300;

  double _aspectRatio = 200 / 300;

  @override
  Widget build(BuildContext context) {
    return Stack(
      overflow: Overflow.visible,
      children: <Widget>[
        Positioned(
          top: _y,
          left: _x,
          child: GestureDetector(
            onPanUpdate: (DragUpdateDetails details) {
              setState(() {
                _x += details.delta.dx;
                _y += details.delta.dy;
              });
            },
            child: Image.network(
              "https://via.placeholder.com/300x200",
              width: _width,
            ),
          ),
        ),

        // top left
        Positioned(
          top: _y - ballRadius,
          left: _x - ballRadius,
          child: Ball(
            onDragStart: () {},
            onDrag: (double dx, double dy) {},
            onDragEnd: () {},
          ),
        ),

        // top middle
        Positioned(
          top: _y - ballRadius,
          left: _x + _width / 2 - ballRadius,
          child: Ball(
            onDragStart: () {},
            onDrag: (double dx, double dy) {},
            onDragEnd: () {},
          ),
        ),

        // top right
        Positioned(
          top: _y - ballRadius,
          left: _x + _width - ballRadius,
          child: Ball(
            onDragStart: () {},
            onDrag: (double dx, double dy) {},
            onDragEnd: () {},
          ),
        ),

        // middle left
        Positioned(
          top: _y + _height / 2 - ballRadius,
          left: _x - ballRadius,
          child: Ball(
            onDragStart: () {},
            onDrag: (double dx, double dy) {},
            onDragEnd: () {},
          ),
        ),

        // middle right
        Positioned(
          top: _y + _height / 2 - ballRadius,
          left: _x + _width - ballRadius,
          child: Ball(
            onDragStart: () {},
            onDrag: (double dx, double dy) {},
            onDragEnd: () {},
          ),
        ),

        // bottom left
        Positioned(
          top: _y + _height - ballRadius,
          left: _x - ballRadius,
          child: Ball(
            onDragStart: () {},
            onDrag: (double dx, double dy) {},
            onDragEnd: () {},
          ),
        ),

        // bottom middle
        Positioned(
          top: _y + _height - ballRadius,
          left: _x + _width / 2 - ballRadius,
          child: Ball(
            onDragStart: () {},
            onDrag: (double dx, double dy) {},
            onDragEnd: () {},
          ),
        ),

        // bottom right
        Positioned(
          top: _y + _height - ballRadius,
          left: _x + _width - ballRadius,
          child: Ball(
            onDragStart: () {},
            onDrag: (double dx, double dy) {
              var mid = (dx + dy) / 2;
              var newWidth = _width + 2 * mid;
              var newHeight = newWidth * _aspectRatio;

              setState(() {
                _width = newWidth;
                _height = newHeight;
                _y = _y - dy;
                _x = _x - 2 * dx;
              });
            },
            onDragEnd: () {},
          ),
        ),
      ],
    );
  }
}

class Ball extends StatelessWidget {
  final Function onDragStart;
  final Function onDrag;
  final Function onDragEnd;

  const Ball({this.onDragStart, this.onDrag, this.onDragEnd});

  void _onDragStart(DragStartDetails details) {
    if (onDragStart != null) onDragStart();
  }

  void _onDragUpdate(DragUpdateDetails details) {
    if (onDrag != null) onDrag(details.delta.dx, details.delta.dy);
  }

  void _onDragEnd(DragEndDetails details) {
    if (onDragEnd != null) onDragEnd();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanStart: _onDragStart,
      onPanUpdate: _onDragUpdate,
      onPanEnd: _onDragEnd,
      child: Container(
        height: 2 * ballRadius,
        width: 2 * ballRadius,
        decoration: BoxDecoration(
          color: Colors.blue,
          borderRadius: BorderRadius.circular(ballRadius),
          border: Border.all(
            width: 3,
            color: Colors.white,
          ),
        ),
      ),
    );
  }
}

My goal is to uniformly resize like the following:

However, currently, it looks like this.

As you can see that the x and y coordinates are messed up. The goal here is if you resize the image from the bottom right corner then the image will stay at the top left corner. Please help with this. Thanks.


回答1:


i change the the top left positioned like this

 // top left
    Positioned(
      top: _y - ballRadius,
      left: _x - ballRadius,
      child: Ball(
        onDragStart: () {},
        onDrag: (double dx, double dy) {
          var newWidth = _width - dx;
          var newHeight = newWidth * _aspectRatio;
          setState(() {
            _y = _y + (_height - newHeight);
            _x = _x + dx;
            _width = newWidth ;
            _height = newHeight;
          });
        },
        onDragEnd: () {},
      ),
    ),

and bottom right positioned (just for completing Answer)

        Positioned(
      top: _y + _height - ballRadius,
      left: _x + _width - ballRadius,
      child: Ball(
        onDragStart: () {},
        onDrag: (double dx, double dy) {

          var newWidth = _width + dx;
          var newHeight = newWidth * _aspectRatio;

          setState(() {
            _width = newWidth ;
            _height = newHeight;
          });
        },
        onDragEnd: () {},
      ),
    ),

and adding this parameter to image.network

fit: BoxFit.fill,

full code at here : https://dartpad.dev/44adae92cecbd2dddc00f264293e5c3a




回答2:


Take a look at a brand new widget implemented in Flutter 1.20, InteractiveViewer. It allows you to zoom and pan a child.

You could also use a combination of GestureDetector and StatefulBuilder to update a child every time you drag your finger



来源:https://stackoverflow.com/questions/63951617/create-a-resizable-view-in-flutter

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!