How to use SupportMapFragment inside a Fragment?
Asked Answered
P

5

22

I know that there has been an issue in using a nested fragment. But my application was designed to run on fragments and if i will be using activity for the map, my casting functions will have error.

I would like to ask help from you on how to achieve this. I've been searching in the internet but i couldn't find best solution.

I've tried this code:

private void setUpMapIfNeeded() {
    // Do a null check to confirm that we have not already instantiated the map.
    if (mMap == null) {
        // Try to obtain the map from the SupportMapFragment.
        mMap = ((SupportMapFragment) myFragmentActivity.getSupportFragmentManager().findFragmentById(R.id.map_con))
                .getMap();
        // Check if we were successful in obtaining the map.
        if (mMap != null) {
            mMap.setMyLocationEnabled(true);
        }
    }
}

this would give me duplicate error because of R.id.map_con is a fragment inside my fragment.

So I look for a work around, this time, R.id.map_con is a frame layout and in the run time I created the SupportMapFragment to it.

SupportMapFragment mSupportMapFragment = new SupportMapFragment();
    myFragmentActivity.getSupportFragmentManager().beginTransaction()
            .replace(R.id.map_con, mSupportMapFragment).commit();

though this does not give me a duplicate every time a close and open the fragment. but my error is that mSupportMapFragment.getMap is always null., I don't get it why its null?.

mMap = mSupportMapFragment.newInstance().getMap();
        if (mMap != null){
            Log.e("ReportFragment","mMap is not empty");
        }else{
            Log.e("ReportFragment","mMap is empty");
        }

I would really appreciate any inputs from you guys, or do you have another work around but still in this process, i.e Fragment inside fragment

Thanks

chkm8

Piperpiperaceous answered 31/7, 2014 at 5:11 Comment(0)
P
19

I just met my luck, while making this post,I found what Im looking for.

I have used this:

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_location, container, false);
    mMapFragment = new SupportMapFragment() {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            mMap = mMapFragment.getMap();
            if (mMap != null) {
                setupMap();
            }
        }
    };
    getChildFragmentManager().beginTransaction().add(R.id.framelayout_location_container, mMapFragment).commit();
return v;   
}

Credit to this Old post

Piperpiperaceous answered 31/7, 2014 at 5:32 Comment(3)
what is the implementation of setupMap() method?Becka
now i'm having crash with the message "java.lang.IllegalArgumentException: The concrete class implementing IObjectWrapper must have exactly one declared private field for the wrapped object. Preferably, this is an instance of the ObjectWrapper<T> class." with play-services-location:9.0.2 please help me out.Napalm
instaed of this your can call mMapFragment.getMapAsync and getMap theirFribble
S
67

getMap() is deprecated

The code should be something like this in a Fragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.fragment_location, container, false);

    mMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
    mMapFragment.getMapAsync(this);

    return v;   
}
Sororicide answered 11/2, 2017 at 13:59 Comment(5)
This is the only answer that worked for me from a dozen or so SO posts and web articles.Dolt
This worked for me, And technically yes, getChildFragmentManager() is the correct answer. Thanks @lpfx.Nicholson
this correct answer for this question, please up vote for this answer so people will get resolved problem as early possible.Hammock
This should be the accepted answer since in essence we are calling a fragment within a fragment then getChildFragmentManager() should be invokedBuss
In this way after go main fragment to back stack and then pop back map is too laggyTemplin
P
19

I just met my luck, while making this post,I found what Im looking for.

I have used this:

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_location, container, false);
    mMapFragment = new SupportMapFragment() {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            mMap = mMapFragment.getMap();
            if (mMap != null) {
                setupMap();
            }
        }
    };
    getChildFragmentManager().beginTransaction().add(R.id.framelayout_location_container, mMapFragment).commit();
return v;   
}

Credit to this Old post

Piperpiperaceous answered 31/7, 2014 at 5:32 Comment(3)
what is the implementation of setupMap() method?Becka
now i'm having crash with the message "java.lang.IllegalArgumentException: The concrete class implementing IObjectWrapper must have exactly one declared private field for the wrapped object. Preferably, this is an instance of the ObjectWrapper<T> class." with play-services-location:9.0.2 please help me out.Napalm
instaed of this your can call mMapFragment.getMapAsync and getMap theirFribble
F
7

I have used it in the given manner and it's working fine.

It's also working with getChildFragmentManager()

MapyFragment

public class MapyFragment extends Fragment implements OnMapReadyCallback {

    private Context mContext;
    private SupportMapFragment supportMapFragment;
    private GoogleMap map;
    private MarkerOptions currentPositionMarker = null;
    private Marker currentLocationMarker;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mContext = getActivity();
        return inflater.inflate(R.layout.fragment_mapy, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mContext = getActivity();

        FragmentManager fm = getActivity().getSupportFragmentManager();/// getChildFragmentManager();
        supportMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
        if (supportMapFragment == null) {
            supportMapFragment = SupportMapFragment.newInstance();
            fm.beginTransaction().replace(R.id.map_container, supportMapFragment).commit();
        }
        supportMapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        map = googleMap;
        if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        map.setMyLocationEnabled(true);
        map.animateCamera(CameraUpdateFactory.zoomTo(15));
        /*map.setOnMapLongClickListener(MapyFragment.this);
        map.setOnMapClickListener(MapFragment.this);*/
    }

    public void updateCurrentLocationMarker(Location currentLatLng){

        if(map != null){

            LatLng latLng = new LatLng(currentLatLng.getLatitude(),currentLatLng.getLongitude());
            if(currentPositionMarker == null){
                currentPositionMarker = new MarkerOptions();

                currentPositionMarker.position(latLng)
                        .title("My Location").
                        icon(BitmapDescriptorFactory.fromResource(R.drawable.start_blue));
                currentLocationMarker = map.addMarker(currentPositionMarker);
            }

            if(currentLocationMarker != null)
                currentLocationMarker.setPosition(latLng);

            ///currentPositionMarker.position(latLng);
            map.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        }
    }
}

and fragment_mapy.xml

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    android:id="@+id/map_container"
    class="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    map:uiZoomControls="true" />
Fribble answered 10/2, 2017 at 13:48 Comment(0)
G
4

In kotlin it could be done as follows:

class NameFragment: Fragment(){
    // other code ...
    private lateinit var googleMapsFragment: SupportMapFragment

    override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View {
         googleMapsFragment = childFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment
        // other code ...
    }
}
Godhead answered 11/9, 2019 at 21:35 Comment(0)
Z
1

Create SupportMapFragment in Java?

You can also create SupportMapFragment inside a Fragment like this.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_maps, parent, false);
    SupportMapFragment supportMapFragment = SupportMapFragment.newInstance();

    getChildFragmentManager()
        .beginTransaction()
        .add(R.id.mapContainer, supportMapFragment)
        .commit();

    supportMapFragment.getMapAsync(this::onMapReady);
    
    return view;
}

Here is the code for layout R.layout.fragment_maps

<androidx.coordinatorlayout.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
       android:id="@+id/map"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
    />
    <!-- Other Widgets like FAB, Bottomsheet-->
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Note:

It is a common practice for inflating a fragment in Activities.

  • Create an instance of the fragment
  • Inflate it in a fragment container

So I took the same approach for inflating SupportMapFragment inside a Fragment.

Zacharie answered 23/12, 2020 at 23:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.