Как получить положение (координаты) виджета на экране в Flutter?

«Как получить положение (координаты) виджета на экране в Flutter?» — вопрос из категории UI и вёрстка, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для получения координат виджета относительно экрана используется комбинация GlobalKey и RenderBox. Вот практический пример:

class WidgetPositionExample extends StatefulWidget {
  @override
  _WidgetPositionExampleState createState() => _WidgetPositionExampleState();
}

class _WidgetPositionExampleState extends State<WidgetPositionExample> {
  final GlobalKey _widgetKey = GlobalKey();
  Offset? _position;
  Size? _size;

  void _getPosition() {
    // Получаем координаты после отрисовки виджета
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final renderBox = _widgetKey.currentContext?.findRenderObject() as RenderBox?;

      if (renderBox != null && renderBox.hasSize) {
        setState(() {
          // Получаем координаты относительно экрана
          _position = renderBox.localToGlobal(Offset.zero);
          _size = renderBox.size;
        });

        print('Position: (${_position!.dx}, ${_position!.dy})');
        print('Size: ${_size!.width} x ${_size!.height}');
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Container(
          key: _widgetKey,
          width: 150,
          height: 100,
          color: Colors.blue,
          alignment: Alignment.center,
          child: Text('Target Widget', style: TextStyle(color: Colors.white)),
        ),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: _getPosition,
          child: Text('Get Position'),
        ),
        if (_position != null)
          Text('Position: (${_position!.dx.toStringAsFixed(1)}, ${_position!.dy.toStringAsFixed(1)})'),
      ],
    );
  }
}

Ключевые аспекты:

  1. GlobalKey — уникальный ключ, который позволяет получить доступ к состоянию и контексту виджета
  2. findRenderObject() — получает RenderObject виджета, который содержит информацию о размере и положении
  3. localToGlobal(Offset.zero) — преобразует локальные координаты виджета (относительно его родителя) в глобальные координаты экрана
  4. addPostFrameCallback — гарантирует, что вычисления выполняются после полной отрисовки виджета

Важно: Этот метод работает только для виджетов, которые уже отрендерены и имеют размер (hasSize == true).