有没有办法在 FittedBox 中获取图像的真实大小/位置?

Is there a way to get the real size / position of Image in a FittedBox?

我有一个简单的布局,其中包含一个封装在 FittedBox 中的图像小部件。我想获取它的大小和位置,所以我在 Image 小部件上放了一个键并从 initState 中获取它:

final GlobalKey imgKey = GlobalKey();



@override
void initState() {
  SchedulerBinding.instance?.addPostFrameCallback((timeStamp) async {
    await ModalRoute.of(context)?.didPush(); //wait opening transition
    final keyPosContext = imgKey.currentContext;
    if (keyPosContext != null){
      final renderPlan = keyPosContext.findRenderObject() as RenderBox;
      final pos = renderPlan.localToGlobal(Offset.zero);
      if(pos != planOffset || renderPlan.size != planSize) {
        setState(() {
          planOffset = pos;
          planSize = renderPlan.size;
        });
      }
    }
  });
  super.initState();
}

布局:

Widget build(BuildContext context){
  return Stack(
    children: [
      Positioned(
        top: 0, left: 100, right: 100, height: 30,
        child: Align(alignment: Alignment.center,
          child: Text('$title'),
        ), 
      ),  
      Positioned(
        top: 30, left: 0, right: 0, bottom: 0,
        child: DragTarget<DraggableData>(
          onMove: onMove,
          onAccept: onAccept,
          builder: (BuildContext context, List candidateData, List rejectedData) {
            File img = File(myPlan);
            if (img.existsSync()) {
              return FittedBox(
                fit: BoxFit.contain,
                child: Image.file(img, key: imgKey),
              );
            } else
              return Container();
          }
        ),
      ),
      Positioned(//TEST
        top: planOffset.dy,
        left: planOffset.dx,
        height: planSize.height,
        width: planSize.width,
        child: Container(
          decoration: BoxDecoration(
            border: Border.all(color: Colors.green, width: 2),
          ),
        ),
      ),
    ]
  );
}

最后一个 Positioned 只是一个用来测试值的绿色矩​​形。我采取了正确的位置,但尺寸不对:我采用原始图像尺寸(在我的情况下为 400*300),而不管合适的尺寸...

您可以使用此小部件在 运行 时获取尺寸。

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

typedef void OnWidgetSizeChange(Size size);

class MeasureSize extends SingleChildRenderObjectWidget {
  final OnWidgetSizeChange onChange;

  const MeasureSize({Key? key, required this.onChange, required Widget child}) : super(key: key, child: child);

  @override
  RenderObject createRenderObject(BuildContext context) => _MeasureSizeRenderObject(onChange);
}

class _MeasureSizeRenderObject extends RenderProxyBox {
  Size? oldSize;
  final OnWidgetSizeChange onChange;

  _MeasureSizeRenderObject(this.onChange);

  @override
  void performLayout() {
    super.performLayout();

    Size newSize = child!.size;
    // if (oldSize == newSize) return;

    oldSize = newSize;
    WidgetsBinding.instance!.addPostFrameCallback((_) => onChange(newSize));
  }
}

获取尺寸

      ...
      Positioned(
        top: 30, left: 0, right: 0, bottom: 0,
        child: DragTarget<DraggableData>(
          onMove: onMove,
          onAccept: onAccept,
          builder: (BuildContext context, List candidateData, List rejectedData) {
            File img = File(myPlan);
            if (img.existsSync()) {
              return FittedBox(
                fit: BoxFit.contain,
                child: MeasureSize(
                  child: Image.file(img, key: imgKey),
                  onChange: (Size newSize) {
                    setState(() {
                      planSize = newSize;
                    });
                  },
                ),
              );
            } else
              return Container();
          }
        ),
      ),
      ...

感谢@Dennis Mwea 抽出时间提供解决方案,我只是为了我的目的添加了小部件偏移量,但它非常完美。

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

typedef void OnWidgetSizeChange(Size size, Offset pos);

class MeasuredWidget extends SingleChildRenderObjectWidget {
  final OnWidgetSizeChange onChange;

  const MeasuredWidget({Key? key, required this.onChange, required Widget child}) : super(key: key, child: child);

  @override
  RenderObject createRenderObject(BuildContext context) => _MeasureWidgetRenderObject(onChange);
}

class _MeasureWidgetRenderObject extends RenderProxyBox {
  Size? oldSize;
  Offset? oldPos;

  final OnWidgetSizeChange onChange;

  _MeasureWidgetRenderObject(this.onChange);

  @override
  void performLayout() {
    super.performLayout();

    WidgetsBinding.instance!.addPostFrameCallback((_){ 
      Size newSize = child!.size;
      Offset newPos = child!.localToGlobal(Offset.zero);
      if (oldSize == newSize && oldPos == newPos) return;
      oldSize = newSize;
      oldPos = newPos;
      onChange(newSize, newPos));
  }
}