You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin Forms Android端AdMob自适应横幅广告显示异常问题求助

AdMob自适应横幅显示异常修正方案

核心根因定位

所有异常的触发点集中在三个实现偏差:

  • 静态全局AdView实例导致不同页面的渲染器交叉复用控件,篡改控件参数
  • 上下文传值错误导致AdSize计算逻辑拿到的屏幕参数不准
  • 原生广告视图和Xamarin.Forms层的高度测量逻辑未打通,视图高度为0或被父容器强制裁切

1. 共享层自定义视图重构

直接替换原有的Frame基类自定义视图,去掉Frame自带的圆角、阴影、默认Padding对原生广告视图的布局干扰。新增高度绑定属性,用于和原生侧的广告实际尺寸做同步:

using Xamarin.Forms;
namespace MyApp.Views
{
    public class AdAdaptiveBannerView : View
    {
        public static readonly BindableProperty AdHeightProperty = BindableProperty.Create(
            propertyName: nameof(AdHeight),
            returnType: typeof(double),
            declaringType: typeof(AdAdaptiveBannerView),
            defaultValue: 0d);
        public double AdHeight
        {
            get => (double)GetValue(AdHeightProperty);
            set => SetValue(AdHeightProperty, value);
        }
    }
}

2. Android侧自定义渲染器重构

替换原有的静态实例实现,修复上下文传值错误,打通原生视图和Forms层的高度测量链路:

[assembly: ExportRenderer(typeof(MyApp.Views.AdAdaptiveBannerView), typeof(MyApp.Droid.AdAdaptiveBanner_Droid))]
namespace MyApp.Droid
{
    public class AdAdaptiveBanner_Droid : ViewRenderer<Views.AdAdaptiveBannerView, AdView>
    {
        private AdView _nativeAdView;
        public AdAdaptiveBanner_Droid(Context context) : base(context)
        {
        }

        private AdView CreateAdView()
        {
            // 用当前Activity上下文初始化AdView,不要使用全局Application上下文
            _nativeAdView = new AdView(Context)
            {
                AdUnitId = "ca-app-pub-3940256099942544/6300978111"
            };

            // 手动计算当前屏幕可用宽度,跳过系统导航栏占用的区域
            var metrics = Resources.DisplayMetrics;
            int adWidthDp = (int)(metrics.WidthPixels / metrics.Density);
            // 用当前Activity上下文计算自适应尺寸,避免全局上下文拿不到屏幕方向参数
            var adSize = AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSize(Context, adWidthDp);
            _nativeAdView.AdSize = adSize;

            // 固定布局参数:宽度匹配父容器,高度自适应广告内容
            _nativeAdView.LayoutParameters = new LayoutParams(LayoutParams.MatchParent, LayoutParams.WrapContent);

            _nativeAdView.AdListener = new BannerAdListener(this, _nativeAdView);
            _nativeAdView.LoadAd(new AdRequest.Builder().Build());
            return _nativeAdView;
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Views.AdAdaptiveBannerView> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement == null) return;
            if (Control == null)
            {
                SetNativeControl(CreateAdView());
            }
        }

        // 补充屏幕旋转适配:配置变化时重新计算尺寸、重新加载广告
        protected override void OnConfigurationChanged(Configuration newConfig)
        {
            base.OnConfigurationChanged(newConfig);
            // 销毁旧的广告实例
            _nativeAdView.Destroy();
            // 重新创建广告实例、计算新方向下的AdSize
            SetNativeControl(CreateAdView());
        }

        // 页面销毁时释放资源,避免内存泄漏
        protected override void Dispose(bool disposing)
        {
            if (disposing && _nativeAdView != null)
            {
                _nativeAdView.AdListener = null;
                _nativeAdView.Destroy();
                _nativeAdView = null;
            }
            base.Dispose(disposing);
        }
    }

    // 广告加载完成后同步实际高度到Forms视图
    internal class BannerAdListener : AdListener
    {
        private readonly AdAdaptiveBanner_Droid _renderer;
        private readonly AdView _adView;
        public BannerAdListener(AdAdaptiveBanner_Droid renderer, AdView adView)
        {
            _renderer = renderer;
            _adView = adView;
        }
        public override void OnAdLoaded()
        {
            base.OnAdLoaded();
            // 将原生广告的像素高度转换为Forms可识别的dp单位
            double adHeightDp = _adView.AdSize.Height / Resources.DisplayMetrics.Density;
            // 同步到Forms视图的高度属性,避免被父容器裁切
            _renderer.Element.AdHeight = adHeightDp;
            _renderer.Element.HeightRequest = adHeightDp;
        }
    }
}

3. 页面XAML布局修正

去掉多余的嵌套容器,把广告视图固定在页面底部,绑定同步过来的实际广告高度:

<ContentPage.Content>
    <StackLayout VerticalOptions="FillAndExpand">
        <!-- 页面原有业务内容放置在该区域 -->
        <StackLayout VerticalOptions="End">
            <views:AdAdaptiveBannerView
                HorizontalOptions="FillAndExpand"
                HeightRequest="{Binding AdHeight}"
                Margin="0"/>
        </StackLayout>
    </StackLayout>
</ContentPage.Content>

异常效果对应排查点

  • 广告宽度随机变化:删除原代码中静态全局的adView实例,改为每个渲染器持有独立的_nativeAdView实例,避免多页面交叉复用篡改参数
  • 广告底部被裁切:检查是否在OnAdLoaded回调里同步了广告的实际高度到Forms视图,不要依赖父容器自动测量高度
  • 去掉Frame后广告消失:确认高度同步逻辑正常运行,避免视图实际高度为0
  • SmartBanner显示多余边框:确认AdView初始化时传入的是当前Activity上下文,而非全局Application上下文,避免安全区计算错误

内容的提问来源于stack exchange,提问作者Robot Head

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 03:45:05