如何在Flutter中获取小部件的大小?

tpgth1q7  于 2023-03-31  发布在  Flutter
关注(0)|答案(5)|浏览(190)

我遇到了这个例子来获取小部件的大小/位置:https://medium.com/@diegoveloper/flutter-widget-size-and-position-b0a9ffed9407
我的代码有什么问题?
我得到错误:

The following NoSuchMethodError was thrown while handling a gesture:
I/flutter ( 8566): The method 'findRenderObject' was called on null.
I/flutter ( 8566): Receiver: null
I/flutter ( 8566): Tried calling: findRenderObject()
void main() {
      runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: MyWidgetSizeTMP());
  }
}

class MyWidgetSizeTMP extends StatefulWidget{
  @override
  MyWidgetSizeTMPState createState() {
    return new MyWidgetSizeTMPState();
  }
}

class MyWidgetSizeTMPState extends State<MyWidgetSizeTMP> {

  //creating Key for red panel
  GlobalKey _keyRed = GlobalKey();

  _getSizes() {
    final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
    final sizeRed = renderBoxRed.size;
    print("SIZE of Red: $sizeRed");
  }

  _getPositions() {
    final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
    final positionRed = renderBoxRed.localToGlobal(Offset.zero);
    print("POSITION of Red: $positionRed ");
  }

  _afterLayout(_) {
    _getSizes();
    _getPositions();
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
      ),
      body: Column(
        children: <Widget>[
          Flexible(
            flex: 2,
            child: Container(
              color: Colors.red,
            ),
          ),
          Flexible(
            flex: 1,
            child: Container(
              color: Colors.purple,
            ),
          ),
          Flexible(
            flex: 3,
            child: Container(
              color: Colors.green,
            ),
          ),
          Spacer(),
          Padding(
            padding: const EdgeInsets.only(bottom: 8.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                MaterialButton(
                  elevation: 5.0,
                  padding: EdgeInsets.all(15.0),
                  color: Colors.grey,
                  child: Text("Get Sizes"),
                  onPressed: _getSizes,
                ),
                MaterialButton(
                  elevation: 5.0,
                  color: Colors.grey,
                  padding: EdgeInsets.all(15.0),
                  child: Text("Get Positions"),
                  onPressed: _getPositions,
                )
              ],
            ),
          )
        ],
      ),
    );
  }
}
niwlg2el

niwlg2el1#

您可以在LayoutBuilder中换行:

return LayoutBuilder(
    builder: (BuildContext context, BoxConstraints constraints) {
//      height: constraints.maxHeight,
//      width: constraints.maxWidth
        return YourWidget();
    }
);
kpbwa7wx

kpbwa7wx2#

这是因为_keyRed没有附加到代码中的Context。
要修复它:

@override
Widget build(BuildContext context) {
  return Scaffold(
    key: _keyRed,  // Add this.
    appBar: AppBar(
kyvafyod

kyvafyod3#

在您提到的链接中,创建GlobalKey后会分配给red容器。
但是在你的代码中,你还没有把它赋值给容器,所以可以从**_getSizes()_getPositions()中引用它,_keyRed**必须在你的代码中附加到Context中才能使用。

// Creating Key for red panel
GlobalKey _keyRed = GlobalKey();

    ...

    // Set key
    Flexible(
        flex: 2,
        child: Container(
            key: _keyRed, // Assigned as a key of the red container.
            color: Colors.red,
        ),
    ),
nhn9ugyo

nhn9ugyo4#

使用RenderBox获取当前小部件的大小。阅读RenderBox可以为您提供的所有属性。
获取高度的代码:

class _YourWidgetState extends State<YourWidget> {
  // Remember to assign this key to a widget.
  late final GlobalKey _key = GlobalKey();

  ...

  Widget build(BuildContext context) {
     var renderBox = null;
     if (_key.currentContext?.findRenderObject() != null) {
        renderBox = _key.currentContext!.findRenderObject() as RenderBox;
     }

     final height = renderBox?.size.height;

     ...

     return SomeWidget(
        key: _key,
        ...
     )
  }
}

findRenderObject的注意事项:

    • “此方法仅在生成阶段完成后返回有效结果。因此,从生成方法调用此方法无效。只能从交互事件处理程序(例如,手势回调)或布局或绘制回调调用此方法。如果State.mounted返回false,则调用此方法也无效。"*
    • “调用这个方法在理论上是相对昂贵的(在树的深度上是O(N)),但在实践中通常是便宜的,因为树通常有很多渲染对象,因此到最近的渲染对象的距离通常很短。"* 这意味着我的代码可以改进,因为每次调用build()时都会调用findRenderObject()
gmol1639

gmol16395#

没有任何直接的方法来计算小部件的大小,所以我们必须借助小部件的上下文。
调用 context.size 会返回Size对象,其中包含小部件的高度和宽度。context.size 计算小部件的渲染框并返回大小。
退房 Flutter: How to get the height of the widget?

相关问题