Выделите фиксированное пространство для адаптивной баннерной рекламы

#android #android-layout #kotlin #admob

#Android #android-макет #kotlin #admob

Вопрос:

Как мне выделить фиксированное пространство для адаптивных рекламных баннеров?

Мой адаптивный баннер XML

     <FrameLayout
    android:id="@ id/ad_view_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:layout_alignParentBottom="true"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    />
  

Внутри моего фрагмента получаем размеры адаптивного рекламного баннера

     private val adSize: AdSize
    get() {
        val outMetrics = Resources.getSystem().displayMetrics;

        val density = outMetrics.density

        var adWidthPixels = adContainerView.width.toFloat()
        if (adWidthPixels == 0f) {
            adWidthPixels = outMetrics.widthPixels.toFloat()
        }

        val adWidth = (adWidthPixels / density).toInt()
        return AdSize.getCurrentOrientationBannerAdSizeWithWidth(context, adWidth)
    }
  

Я хотел бы следовать указаниям Google и зарезервировать выделенное фиксированное пространство для моего баннера, чтобы, если мой баннер «зависает» на втором экране на мобильном устройстве, он оставался неизменным.
Как мне это сделать, как правильно?

Ответ №1:

при запуске приложения вы можете сразу получить высоту адаптивного баннера, вызвав что-то вроде adSize.getHeight() . Это даст вам высоту баннера в dps.

Затем вы преобразуете высоту dps в пиксели и программно устанавливаете эту высоту для макета рекламного фрейма, вызывая setLayoutParams с полученной высотой в пикселях.

Таким образом, вам не нужно ждать загрузки объявления, чтобы применить правильную высоту и риск нарушения политики перекрытия рекламы или смещения контекста (что может произойти, если вы зависите от wrap_content)

Ответ №2:

Если у вас более сложное поведение, как у меня, вы можете использовать следующую реализацию. У меня есть ConstraintLayout , который разделяет мой экран на две части в портретном режиме. Баннер находится в пределах одной из этих двух частей, и соотношение между ними не фиксировано, а зависит от некоторой логики. Таким образом, эта реализация также соответствует этому требованию, поскольку она перезаписывает onMeasure для определения наилучшего размера в зависимости от доступной ширины.

 public class AdBanner extends FrameLayout
{
    private AdView mAdView;
    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();

    public AdBanner(Context context)
    {
        super(context);
    }

    public AdBanner(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public AdBanner(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        if (!isShowBanner())
        {
            super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.AT_MOST));
            return;
        }
        int width = MeasureSpec.getSize(widthMeasureSpec);
        if (width <= 0)
        {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            return;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // That's where we determine the most accurate banner format.
        AdSize adSize = AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(getContext(), getDpWidth(width));
        int height = adSize.getHeightInPixels(getContext());
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.UNSPECIFIED)
        {
            height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
        }
        setMeasuredDimension(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.getMode(heightMeasureSpec)));
    }

    protected int getDpWidth(int width)
    {
        Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        display.getMetrics(mDisplayMetrics);
        return (int) (width / mDisplayMetrics.density);
    }

    protected boolean isShowBanner()
    {
        // Do your checks here, like whether the user payed for ad removement.
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        if (!isShowBanner())
        {
            return;
        }
        int width = r - l;
        if (width <= 0)
        {
            return;
        }
        AdSize adSize = AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(getContext(), getDpWidth(width));

        // Prevent the ad from beeing added with each layout cicle,
        // by checking, whether or not available size actually changed the format of the banner
        if (mAdView == null || !adSize.equals(mAdView.getAdSize()))
        {
            removeAllViews();
            mAdView = new AdView(getContext());
            mAdView.setAdSize(adSize);
            ((GameApplication) getContext().getApplicationContext()).androidInjector().getAdService().loadBannerAd(getRootActivity(this), mAdView);
            this.addView(mAdView);
        }
        mAdView.layout(0, 0, width, b - t);
    }
}