Я встречал много людей, которые спрашивают, как получить размер и положение виджетов на экране. В некоторых случаях мы обнаружим, что у нас всегда есть причина для реализации этой функции. Но сам виджет не имеет размера и положения. Для этого мы должны получить RenderBox, связанный с контекстом Widget.Оригинальная ссылка
Автор: Диего Веласкес
Причина лайка: Может лучше отлаживать проблемы с макетом
How do we do this?
Мы можем создать демонстрацию, нарисовать в столбце три панели разных цветов, а именно красную, фиолетовую и зеленую, а затем написать внизу две кнопки: «Получить размеры», «Получить позицию».
фрагмент демо-кода
_getSizes() {
}
_getPositions(){
}
@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,
)
],
),
)
],
),
);
}
Изображение эффекта:
Теперь вопрос: как мне получить размер и положение каждой панели?Давайте сосредоточимся на красной панели выше.Когда мы знаем, как получить ее размер и положение, это будет легко для других панелей.
Получить размер виджета
Чтобы добиться этого, нам нужно, чтобы у нашего виджета был ключ, поэтому нам нужно создать GlobalKey и назначить его нашему виджету.
//creating Key for red panel
GlobalKey _keyRed = GlobalKey();
...
//set key
Flexible(
flex: 2,
child: Container(
key: _keyRed,
color: Colors.red,
),
),
Как только у нашего виджета есть ключ, мы можем получить размер в соответствии с ключом следующим образом.
_getSizes() {
final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
final sizeRed = renderBoxRed.size;
print("SIZE of Red: $sizeRed");
}
Если мы нажмем кнопку «Получить размеры», консоль покажет
flutter: SIZE of Red: Size(375.0, 152.9)
Теперь мы знаем, что ширина и высота красной панели равны 375,0 152,9.
Это очень просто, давайте продолжим получать информацию о местоположении виджета
Получить местоположение виджета
Как и раньше, наш виджет должен иметь значение ключа.Давайте обновим метод, чтобы получить положение виджета, чтобы получить положение виджета относительно верхнего левого угла определенной позиции (в этом примере мы используем 0.0 для представления верхнего левого угла текущего экрана) Рог)
_getPositions() {
final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
final positionRed = renderBoxRed.localToGlobal(Offset.zero);
print("POSITION of Red: $positionRed ");
}
Если вы нажмете кнопку «Получить позиции», в консоли будет напечатано:
flutter: POSITION of Red: Offset(0.0, 76.0)
Это означает, что наш виджет составляет 0,0 на оси X и 76,0 на оси Y (в верхнем левом углу экрана)
Почему 76,0? То есть потому, что в этом случае есть два выше высоты AppBar 76.0
Но~ Что, если я хочу получить размер и положение в начале, а не по нажатию кнопки? Затем попробуйте вызвать наш метод в конструкторе
_MainSizeAndPositionState(){
_getSizes();
_getPositions();
}
Запустите демо, появится сообщение об ошибке
flutter: The following NoSuchMethodError was thrown building Builder:
flutter: The method 'findRenderObject' was called on null.
flutter: Receiver: null
flutter: Tried calling: findRenderObject()
Так что, если мы попытаемся вызвать его из InitState
@override
void initState() {
_getSizes();
_getPositions();
super.initState();
}
Запустите демонстрацию, она немного отличается от текущей, но по-прежнему сообщает об ошибке.
flutter: Another exception was thrown: NoSuchMethodError: The method 'findRenderObject' was called on null.
Так как же нам получить размер и позицию в начале?
Причина вышеуказанной ошибки в том, что наше состояние еще не получило соответствующего контекста.Дополнительную информацию о жизненном цикле виджета можно найти по следующему URL-адресу.medium.com/flutter-com…, на Наггетс перевод есть, но автор отличается от первоисточника, содержание похожее, можно сослатьсяnuggets.capable/post/684490…
Поэтому нам нужно дождаться завершения рендеринга виджета перед его выполнением. Но как это сделать?
Вот простая реализация:
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
super.initState();
}
_afterLayout(_) {
_getSizes();
_getPositions();
}
Это гарантирует, что ваш метод вызывается после рендеринга макета.
Запустите демо еще раз, и вы получите:
flutter: SIZE of Red: Size(375.0, 152.9)
flutter: POSITION of Red: Offset(0.0, 76.0)
наконец! ! !
Вы также можете оставить отзыв о моем другеSimon Lightfootсозданный пакетУниверсальный горячий sirius.org/packages/afan…
Суммировать
Часто мы делаем простые вещи очень сложными. Поэтому необходимо внимательно читать официальную документацию, предоставленную Flutter, ведь мы каждый день узнаем что-то новое.
Вы можете проверить мой исходный код в моем репозитории flutter-samples.GitHub.com/Диего ВЕЛО PE…
Справочная статья
- docs.flutter.IO/flutter/люди…
- medium.com/flutter-com…
- Универсальный горячий sirius.org/packages/afan…
Язык переводчика
Некоторые ссылки в статье нужны~~вы знаете~
Это мой первый перевод, и я перевела его исходя из собственного чувства языка, поправки приветствуются~~~