2

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;
}
Ionut Negru
  • 6,186
  • 4
  • 48
  • 78
  • Why don't you simply put them wrapped in `LinearLayout` in the xml? That's how I did what you described. You can use include for a custom xml layout. – Abdul-Rahman Ahmad May 24 '16 at 14:01
  • I do not have an custom layout set for the map fragment as you can see from the implementation! My map fragment class extend directly the SupportMapFragment, I do not want to touch all that logic for a simple view, this is why I've chosen to override the onCreateView() method. – Ionut Negru May 24 '16 at 14:16
  • 1
    Try add the params to the `addView` like: `wrapper.addView(customView, params);` . and some answers on other questions mentioned you might need to initialize the `LinearLayout` with `new` instead of `getLayoutParams()` – Abdul-Rahman Ahmad May 24 '16 at 14:42
  • Using the method with layout params won't fix the issue. The issue was because I was giving the wrong root when inflating, thus creating and setting a wrong parent. Budius answer is the correct one for this case. Still your answer is partially correct as using a new layout object is also an solution (although it overrides the params in the xml and you need to manually set the rules). I've included an solution with using a new layout params object in the question. – Ionut Negru May 24 '16 at 15:15
  • I found Budius's to be logically correct, but I thought it didn't work as you didn't reply him at that time. Glad it all worked out. – Abdul-Rahman Ahmad May 24 '16 at 15:34

1 Answers1

2

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);
Budius
  • 39,391
  • 16
  • 102
  • 144
  • You are right, I've missed out the ViewGroup root parameter of the inflate method. I've used the LinearLayout because the FrameLayout params gave me an class cast exception (but now it makes sense, because I was using the wrong layout params for it). Trying it out now. – Ionut Negru May 24 '16 at 14:29
  • I've marked your answer as the correct one. Thank you for all the help. – Ionut Negru May 24 '16 at 15:13
  • I'm glad I could help. PS. Just for correctness with the LayoutParams, you probably should call `super.onCreateView` passing the `wrapper`. Like this: `View mapView = super.onCreateView(inflater, wrapper, savedInstanceState);` – Budius May 24 '16 at 17:29