Start Debugging

Flutter 3.44: чтение физического радиуса углов экрана из MediaQuery

Flutter 3.44 предоставляет скруглённые углы устройства через MediaQuery.displayCornerRadiiOf. Хватит угадывать волшебный радиус: обрезайте UI по точной кривой оборудования на Android API 31+.

Телефоны перестали иметь прямоугольные экраны много лет назад, но Flutter никогда не сообщал вам, насколько на самом деле скруглены углы. Если вы хотели, чтобы карточка или лист во весь экран повторяли физическую кривую дисплея, вы жёстко прописывали BorderRadius.circular(24), который подбирали на глаз по одному устройству и надеялись, что на остальных всё выглядит нормально. Flutter 3.44, текущая стабильная версия, наконец читает это значение прямо из оборудования и передаёт его вам через MediaQuery.

Значение, которое операционная система уже знала

Android предоставляет радиусы по углам через свой API RoundedCorner начиная с уровня API 31, но фреймворк никогда их не показывал. PR #179219 проводит эти радиусы из оконных метрик движка вверх до MediaQueryData. Вы читаете их так же, как читаете padding или view insets:

final BorderRadius? corners = MediaQuery.displayCornerRadiiOf(context);

Возвращаемый тип: BorderRadius, допускающий null. Каждый угол представляет собой Radius в логических пикселях, поэтому он напрямую сочетается с виджетами, которые вы уже используете. На Android ниже API 31, на iOS и на любой другой платформе значение равно null, поэтому проверка на null становится вашим запасным путём, а не запоздалой мыслью.

Обрезка по кривой оборудования

Очевидное применение: поверхность во весь экран, скругление которой совпадает со стеклом. Раньше вы придумывали число. Теперь вы спрашиваете экран:

@override
Widget build(BuildContext context) {
  final BorderRadius radius =
      MediaQuery.displayCornerRadiiOf(context) ?? BorderRadius.circular(16);

  return ClipRRect(
    borderRadius: radius,
    child: ColoredBox(
      color: Theme.of(context).colorScheme.surface,
      child: content,
    ),
  );
}

Поскольку displayCornerRadii представляет собой настоящий BorderRadius, его четыре угла могут различаться. Это важно на устройствах, где нижний изгиб круче верхнего, или где складной шарнир придаёт одному краю другой профиль. Вы также можете получить один угол, когда нужен только он:

final Radius topLeft =
    (MediaQuery.displayCornerRadiiOf(context) ?? BorderRadius.zero).topLeft;

Физические пиксели, когда они нужны

MediaQuery даёт логические пиксели, что и нужно коду разметки. Если вы работаете на уровне сырых пикселей, например внутри собственного RenderObject или шейдера, те же данные лежат на view: FlutterView.displayCornerRadii возвращает значения в физических пикселях. Выберите тот, что соответствует координатному пространству, в котором вы рисуете, и вы избежите умножения на devicePixelRatio, которое легко перепутать.

Где это действительно окупается

Большинству приложений не нужно попиксельно точное совпадение углов, и SafeArea по-прежнему решает распространённую задачу удержания контента вне выреза. Это для поверхностей, которые читаются как часть самого устройства: нижних листов, поднимающихся до края стекла, иммерсивных медиаплееров, киосковых макетов и новых предиктивных переходов «назад», которые Flutter 3.44 уже подключает к displayCornerRadii, чтобы уходящий экран сжимался в правильно скруглённый прямоугольник.

Функция небольшая, но она закрывает пробел, из-за которого каждая передача работы от дизайнера к разработчику заканчивалась угаданным числом. Трактуйте null как «считай прямоугольным, используй собственную константу», а всё остальное сводится к чтению значения, которое операционная система хранила всё это время. См. документацию по MediaQueryData.displayCornerRadii для полного контракта.

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Назад