androidgoogle-mapsfragmentandroid-custom-viewandroid-gravity

SupportMapFragment with custom view on top


I'm having some issues with customizing SupportMapFragment layout. I basically want to add an custom view at the bottom of the map fragment layout.

I managed to add an view programmatically to the fragment like this:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View mapView = super.onCreateView(inflater, container, savedInstanceState);
    View customView = inflater.inflate(R.layout.custom_view, container, false);

    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) customView.getLayoutParams();
    params.gravity = Gravity.BOTTOM;
    customView.setLayoutParams(params);

    FrameLayout wrapper = new FrameLayout(inflater.getContext());
    wrapper.addView(mapView);
    wrapper.addView(customView);

    return wrapper;
}

The custom_view layout is a simple CardView with no complicated logic:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
        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:id="@+id/custom_view_root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:visibility="gone"
        app:cardBackgroundColor="@color/white"
        >

    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >

            ... some basic content

    </LinearLayout>


</android.support.v7.widget.CardView>

The issue is that my custom view isn't shown at the bottom, but at the top. It seems that the gravity properties I set are not taken into consideration. I've also tried to use an RelativeLayout as an wrapper and manually adding the rule to align the custom view at the bottom, but the result was the same.

LE: As @Budius mentioned in his answer, I overlooked the ViewGorup root parameter of the inflate() method.

This is the correct implementation to use the parameters set in the layout:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    FrameLayout wrapper = new FrameLayout(inflater.getContext());

    View mapView = super.onCreateView(inflater, wrapper, savedInstanceState);
    wrapper.addView(mapView);

    customView = inflater.inflate(R.layout.custom_view, wrapper, false);
    wrapper.addView(customView);

    return wrapper;
}

Another solution for this is to create the params of the custom view programmatically, like this:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View mapView = super.onCreateView(inflater, container, savedInstanceState);
    customView = inflater.inflate(R.layout.custom_view, container, false);
    FrameLayout wrapper = new FrameLayout(inflater.getContext());
    wrapper.addView(mapView);

    FrameLayout.LayoutParams params =
            new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT,
                                         Gravity.BOTTOM);
    wrapper.addView(customView, params);

    return wrapper;
}

Solution

  • the inflater line of code inflater.inflate(R.layout.custom_view, container, false); the container it's meant to indicate LayoutParams to be used from the XML into the parent layout. But then you instantiated a LinearLayout.LayoutParams. And then you added it to a FrameLayout. So it all got discarded because it doesn't match.

    There're a few simple ways to fix it:

    You can inflate the CardView with the proper parent layout:

    // add this line AFTER you created the FrameLayout
    View customView = inflater.inflate(R.layout.custom_view, wrapper, false);
    

    You can inflate the CardView directly inside the wrapper by simply changing to true.

    // this will correctly use the layout params you set on XML and add the inflated views into wrapper
    inflater.inflate(R.layout.custom_view, wrapper, true);
    

    You can create your params as the correct type:

    // use FrameLayout.LayoutParams when using FrameLayout as the parent.
    FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) customView.getLayoutParams();
    params.gravity = Gravity.BOTTOM;
    customView.setLayoutParams(params);