How to put AdView in ConstraintLayout at bottom and below other stuff?

NullPointerException picture NullPointerException · Mar 6, 2018 · Viewed 8k times · Source

I'm trying to migrate from RelativeLayout to ConstraintLayout but I'm having problems adding the AdMob AdView to the bottom and the rest of the content above it. For example, using RelativeLayout was that simple. You only need to put android:layout_alignParentBottom="true" on the AdView and android:layout_above="@+id/adView" on the view which is containing the stuff.

I'm trying to understand how to migrate this sample code and these two lines of code to the equivalent using a ConstraintLayout instead of a RelativeLayout.

Please, can someone help me with this migration?

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/adView"/>

    <com.google.android.gms.ads.AdView
        xmlns:ads="http://schemas.android.com/apk/res-auto"
        android:id="@+id/adView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_marginTop="5dp"
        ads:adSize="BANNER"
        ads:adUnitId="@string/ad_id_banner">
    </com.google.android.gms.ads.AdView>
</RelativeLayout>

I tested using app:layout_constraintBottom_toTopOf="@+id/adView" on the stuff i want above the adView and app:layout_constraintBottom_toBottomOf="parent" on the adView but it's not working because the stuff is not above the adView it's behind. And Also the adView is not centered. It's very frustrating.

Answer

Ben P. picture Ben P. · Mar 6, 2018

First, I want to talk about two pieces of behavior that are unique to ConstraintLayout and that aren't necessarily obvious when you first pick it up.

match_parent is not supported

This detail is tucked away in a one-liner in the developer guide: https://developer.android.com/training/constraint-layout/index.html

Note: You cannot use match_parent for any view in a ConstraintLayout. Instead use "match constraints" (0dp).

To get "match parent" behavior, combine a 0dp dimension with constraints for both corresponding edges of your view:

android:layout_width="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"

Margins are only enforced if they have a corresponding constraint

Just adding android:layout_marginTop will not do anything unless that view also has a top constraint, like app:layout_constraintTop_toTopOf or app:layout_constraintTop_toBottomOf.

Your specific issue

Here's the updated layout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="5dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/adView"/>

    <com.google.android.gms.ads.AdView
        android:id="@+id/adView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:adSize="BANNER"
        app:adUnitId="@string/ad_id_banner"/>

</android.support.constraint.ConstraintLayout>

To achieve the horizontal centering of the AdView, we constrain the left and right edges to the parent's left and right edges. This "pulls" the AdView equally from each side, centering it. To get it to stick to the bottom of the screen, we constrain its bottom edge to the bottom of the parent.

As for the LinearLayout, first we change its dimensions both to 0dp. This will let the constraints define its size. Then we constrain the top, left, and right edges to the top, left, and right edges of the parent. We constrain the bottom edge to the top edge of the AdView. This causes it to fill the screen horizontally, and fill all of the vertical space the AdView isn't using.

Finally, we change the top margin on the AdView into a bottom margin on the LinearLayout. This is because the LinearLayout's bottom edge is constrained to the AdView's top edge (but the AdView's top edge isn't constrained to the LinearLayout's bottom edge, so top margin would have no effect).