Как узнать нужное смещение сверху для показа баннера firebase_admob в iOS?
Я использую плагин firebase_admob для flutter. Неприятная особенность состоит в том, что баннер нельзя встроить в дерево виджетов как обычный виджет, баннер накладывается поверх всего приложения. Но можно задать привязку к верху и смещение по оси Y.
Но тут я столкнулся с проблемой, не могу найти нужное смещение для этого. В андроиде вроде бы всё нормально, я просто получаю позицию по Y самого первого виджета в body (в Scaffold) и это и есть смещение. А вот в iOS к этой величине нужно ещё прибавить отступ сверху, там где показываются часы.
Как видно на скрине баннер немного налазит на AppBar, а должен быть строго под ним.
Сокращённый код виджета такой:
GlobalKey _widgetForAdsStickingKey = GlobalKey();
@override
void initState() {
super.initState();
_bannerAd = buildBannerAd()..load();
}
_getTopOffset() {
final rBox =
_widgetForAdsStickingKey.currentContext.findRenderObject() as RenderBox;
final pos = rBox.localToGlobal(Offset.zero).dy;
var offset = pos;
if (Platform.isIOS) {
offset = pos + MediaQuery.of(context).padding.top;
}
return offset;
}
BannerAd buildBannerAd() {
return BannerAd(
adUnitId: BannerAd.testAdUnitId,
size: AdSize.banner,
listener: (MobileAdEvent event) {
if (event == MobileAdEvent.loaded) {
setState(() {
_add_is_loaded = true;
});
_bannerAd
..show(anchorType: AnchorType.top, anchorOffset: _getTopOffset());
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text('Zeit verfolgen'),
),
backgroundColor: backgroundColor,
body: Center(
key: _widgetForAdsStickingKey,
child: SingleChildScrollView(
child: Padding(
...
Таким образом в методе _getTopOffset() я получаю Y позицию виджета Center, который идёт корневым в body и прибавляю к этой величине отступ сверху до аппбара. Но баннер на iPhone немного накладывается на аппбар.
Может быть я неправильно считаю расстояние от начала экрана до начала области приложения при помощи MediaQuery.of(context).padding.top? Или я не учёл какой-то ещё параметр влияющий на высоту? Помогите как правильно вычислить смещение для баннера, чтобы баннер не накладывался на AppBar.
Ответы (2 шт):
А если так попробовать (MediaQuery.of(context).size.height):
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
double statusBarHeight = MediaQuery.of(context).padding.top;
double appBarHeight = 50.0;
double ad = screenHeight - (statusBarHeight + appBarHeight);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(appBarHeight),
child: AppBar(
title: Text("Test"),
),
),
),
);
}
}
В общем поиски не привели ни к чему положительному.
Во-первых, как я узнал MediaQuery.of(context).padding.top на iOS ниже 11 версии вообще может не срабатывать и выдавать 0 (это причина, по которой на моём реальном устройстве реклама приклеивается прямо поверх статус бара).
Во-вторых, как я выяснил опытным путём, оффсет 0 для баннера в данном плагине не означает реальный верх экрана! Это очень странно, но чтобы реклама показывалась сверху впритык к краю экрана (вверху) надо установить офсет 30. Возможно на это есть какие-то причины, но мне кажется это как-то не адекватно (однако может на iOS 13 таких проблем нет я пока не проверял, у меня эмулятор 12 ios).
Поэтому я решил пойти другим путём, раз этим способом задачу решить не удалось. Я просто поменял привязку рекламы с AnchorType.top на AnchorType.bottom. Однако, я решил, раз на андроиде старый способ работает, то для этой платформы я оставил старый вариант привязки.
А при подсчёте высоты смещения снизу я просто беру высоту экрана и отнимаю от неё положение виджета (на высоте которого должна быть реклама), а также высоту баннера (благо она фиксированная и равна 50).
Таким образом код остался старый лишь с двумя изменениями:
В методе buildBannerAd() я поменял
AnchorType.topнаPlatform.isIOS ? AnchorType.bottom : AnchorType.topВ методе _getTopOffset() я просто заменил строку подсчёта офсета для iOS платформы
offset = MediaQuery.of(context).size.height - 50 - pos;
GlobalKey _widgetForAdsStickingKey = GlobalKey();
@override
void initState() {
super.initState();
_bannerAd = buildBannerAd()..load();
}
_getTopOffset() {
final rBox =
_widgetForAdsStickingKey.currentContext.findRenderObject() as RenderBox;
final pos = rBox.localToGlobal(Offset.zero).dy;
var offset = pos;
if (Platform.isIOS) {
offset = MediaQuery.of(context).size.height - 50 - pos;
}
return offset;
}
BannerAd buildBannerAd() {
return BannerAd(
adUnitId: BannerAd.testAdUnitId,
size: AdSize.banner,
listener: (MobileAdEvent event) {
if (event == MobileAdEvent.loaded) {
setState(() {
_add_is_loaded = true;
});
_bannerAd
..show(anchorType: Platform.isIOS ? AnchorType.bottom : AnchorType.top, anchorOffset: _getTopOffset());
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text('Zeit verfolgen'),
),
backgroundColor: backgroundColor,
body: Center(
key: _widgetForAdsStickingKey,
child: SingleChildScrollView(
child: Padding(
...
