Flutter-获取Widget尺寸的方式

想要获取widget的尺寸,必须要等widget的layout结束之后才能取到,目前有三种方式

  • 通过BuildContext获取
  • 通过GlobalKey获取
  • 通过SizeChangedLayoutNotifier获取

通过BuildContext获取

widget的尺寸存在于context?.findRenderObject()?.paintBounds?.size中,过早获取可能为空,需要延时获取.在flutter1.7之前duration=Duration()就能获取到,但是1.7之后必须要设置一百毫秒以上才行.

class FindSizeWidget extends StatefulWidget {
  @override
  _FindSizeWidgetState createState() => _FindSizeWidgetState();
}

class _FindSizeWidgetState extends State {

  @override
  Widget build(BuildContext context) {
    /// 延时一下,需要等state layout结束之后才能获取size
    Future.delayed(Duration(milliseconds: 100), () {
      _printSize();
    });
    return _buildContentWidget();
  }
  Widget _buildContentWidget(){
    return Container(
      color: Colors.red,
      child: Text(
        '''
        1 ...            1    
        2 ...            2    
        3 ...            3    
        4 ...            4    
        ''',
        style: TextStyle(fontSize: 30),
        maxLines: null,
        softWrap: true,
      ),
    );
  }
  _printSize(){
    if (!mounted) return;
    var size = context?.findRenderObject()?.paintBounds?.size;
    print(size.toString());
  }
}

打印结果:
flutter: Size(277.0, 180.0)

通过GlobalKey获取

FindSizeWidget增加构造方法,通过外部传入GlobalKey,方便以后寻找到FindSizeWidget.context对象.

class FindSizeWidget extends StatefulWidget {
  const FindSizeWidget({Key key}) : super(key:key);
}

注意一个GlobalKey只能对应一个widget对象,当心复用问题.

增加一个获取尺寸的按钮.点击之后获取尺寸.

  class _MyApp extends State {
  GlobalKey _globalKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        FlatButton(
            onPressed: () {
              var size = _globalKey.currentContext
                  ?.findRenderObject()
                  ?.paintBounds
                  ?.size;
              print(size.toString());
            },
            child: Text("获取尺寸")),
        FindSizeWidget(
          key: _globalKey,
        )
      ],
    );
  }
}

打印结果:
flutter: Size(277.0, 180.0)

通过SizeChangedLayoutNotifier获取

使用SizeChangedLayoutNotifier方式,Widget会在layout结束之后会发出一个LayoutChangedNotification通知,我们只需要接收这个通知,即可获取尺寸信息,但是SizeChangedLayoutNotifierRenderObject_RenderSizeChangedWithCallback类,它在第一次布局完成之后并不会发出通知,所以我们要自定义SizeChangedLayoutNotifier_RenderSizeChangedWithCallback两个类.
_RenderSizeChangedWithCallback源码部分:

@override
  void performLayout() {
    super.performLayout();
    // Don't send the initial notification, or this will be SizeObserver all
    // over again!
    if (_oldSize != null && size != _oldSize)
      onLayoutChangedCallback();
    _oldSize = size;
  }

修改_RenderSizeChangedWithCallback,只需要去掉_oldSize != null的判断即可.

@override
  void performLayout() {
    super.performLayout();
    // Don't send the initial notification, or this will be SizeObserver all
    // over again!
    if (size != _oldSize)
      onLayoutChangedCallback();
    _oldSize = size;
  }

再修改_FindSizeWidgetStatebuild方法:

  @override
  Widget build(BuildContext context) {
    return NotificationListener(
      onNotification: (notification) {
        /// 收到布局结束通知,打印尺寸
        _printSize();
        /// flutter1.7之后需要返回值,之前是不需要的.
        return null;
      },
      child: CustomSizeChangedLayoutNotifier(
        child: _buildContentWidget(),
      ),
    );
  }

打印结果:
flutter: Size(277.0, 180.0)

你可能感兴趣的:(Flutter-获取Widget尺寸的方式)