简体   繁体   English

Flutter - 可拖动和缩放的小部件

[英]Flutter - Draggable AND Scaling Widgets

So for this application (Windows, Web) I have 2 requirements:所以对于这个应用程序(Windows,Web)我有两个要求:

  1. User can drag around widgets on the screen (drag and drop) to any location.用户可以将屏幕上的小部件拖动(拖放)到任何位置。
  2. The app must scale to screen/window size该应用程序必须缩放到屏幕/窗口大小

For (1) I used this answer .对于 (1) 我使用了这个答案 For (2) I used this solution .对于 (2) 我使用了这个解决方案

As mentioned in the code comment below I can't have both:正如下面的代码注释中提到的,我不能同时拥有:

If I set logicWidth and logicHeight dynamically depending on the window size, the dragging works fine but the draggable widgets won't scale but instead stay the same size regardless of the window size.如果我根据窗口大小动态设置logicWidthlogicHeight ,则拖动工作正常,但可拖动的小部件不会缩放,而是保持相同的大小,而不管窗口大小如何。

If I set logicWidth and logicHeight to a constant value (the value of the current cleanHeight ) the dragging will be messed up for other screen sizes but then the draggable widgets will scale correctly with the window size.如果我将logicWidthlogicHeight设置为一个常量值(当前cleanHeight的值),对于其他屏幕尺寸,拖动将被弄乱,但可拖动的小部件将随窗口尺寸正确缩放。

In other words: for the dragging to work nicely these values need to be matching the window size at any time.换句话说:为了使拖动能够很好地工作,这些值需要随时与窗口大小相匹配。 But by changing these values I ruin the scaling I need.但是通过更改这些值,我破坏了我需要的缩放比例。

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:matrix_gesture_detector/matrix_gesture_detector.dart';

//containing widgets to drag around
const List<Widget> draggableWidgets = [
  DraggableWidget(
      draggableWidget: CircleAvatar(
    backgroundColor: Colors.green,
    radius: 32,
  )),
  DraggableWidget(
      draggableWidget: CircleAvatar(
    backgroundColor: Colors.red,
    radius: 24,
  )),
];

class FrontPageWidget extends ConsumerWidget {
  const FrontPageWidget({Key? key}) : super(key: key);
  static const routeName = '/frontPage';

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    //screen height and padding
    final height = MediaQuery.of(context).size.height;
    final padding = MediaQuery.of(context).viewPadding;
    // Height (without status and toolbar)
    final cleanHeight = height - padding.top - kToolbarHeight;

    //either make those values dynamic (cleanHeight updates depending on screen size / window size) OR constant (961px is the cleanHeight on full screen)
    //if values are dynamic => the draggable widgets not scaling to screen size BUT dragging works fine
    //if values are constant => the draggable widgets do scale to screen size BUT dragging is messed
    final logicWidth = cleanHeight; //961
    final logicHeight = cleanHeight; //961

    return Scaffold(
      appBar: AppBar(
        title: const Text('Main Page'),
      ),
      body: SizedBox.expand(
          child: FittedBox(
              fit: BoxFit.contain,
              alignment: Alignment.center,
              child: Container(
                color: Colors.grey,
                width: logicWidth,
                height: logicHeight,
                child: Stack(
                  children: draggableWidgets,
                ),
              ))),
    );
  }
}

class DraggableWidget extends StatelessWidget {
  final Widget draggableWidget;
  const DraggableWidget({Key? key, required this.draggableWidget})
      : super(key: key);
  @override
  Widget build(BuildContext context) {
    final ValueNotifier<Matrix4> notifier = ValueNotifier(Matrix4.identity());
    return Center(
      child: MatrixGestureDetector(
        onMatrixUpdate: (m, tm, sm, rm) {
          notifier.value = m;
        },
        child: AnimatedBuilder(
          animation: notifier,
          builder: (ctx, child) {
            return Transform(
              transform: notifier.value,
              child: Center(
                child: Stack(
                  children: [draggableWidget],
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

One way of doing it is wrapping the draggableWidget in a Transform widget and set the scale factor in relation to the dimensions:一种方法是将draggableWidget包装在Transform小部件中,并设置与尺寸相关的scale因子:

   child: AnimatedBuilder(
      animation: notifier,
      builder: (ctx, child) {
        final height = MediaQuery.of(context).size.height;
        return Transform(
          transform: notifier.value,
          child: Center(
            child: Stack(
              children: [
                Transform.scale(
                    scale: height / 1000,
                    child: draggableWidget)
              ],
            ),
          ),
        );
      },
    ),

I had a similar issue, instead of getting the height from the MediaQuery get it from the LayoutBuilder, I noticed it is working much better when resizing the window.我有一个类似的问题,而不是从 MediaQuery 获取高度,而是从 LayoutBuilder 获取高度,我注意到它在调整窗口大小时工作得更好。

body: LayoutBuilder(
    builder: (context, constraints) {
        return SizedBox.expand(
            child: FittedBox(
                fit: BoxFit.contain,
                alignment: Alignment.center,
                child: Container(
                    color: Colors.grey,
                    width: constraints.maxWidth,
                    height: constraints.maxHeight,
                    child: Stack(
                        children: draggableWidgets,
                    ),
                )
            )
        );
    }
);

Another way of achieving this:实现这一目标的另一种方法:
To drag around widgets on the screen (drag and drop) to any location.将屏幕上的小部件拖动(拖放)到任何位置。

And to scale screen/window size.并缩放屏幕/窗口大小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM