Inicializar MapFragment mediante progtwigción con Maps API v2

Estoy tratando de agregar un MapFragment a mi Fragmento actual. El uso de fragmentos nesteds está restringido a FragmentTransactions, no puede usar la etiqueta xml en su diseño. Además, quiero que se agregue al Fragmento principal cuando el usuario presiona un botón. Entonces, estoy creando MapFragment programáticamente con getInstance() cuando el usuario presiona ese botón y lo agrega al lugar correcto. Se muestra correctamente, hasta ahora todo bien.

El problema es que después de adjuntar MapFragment necesito obtener una referencia a GoogleMap para colocar un Marker , pero el método getMap() devuelve null (ya que el fragmento onCreateView() aún no ha sido llamado).

Miré el código de ejemplo de demostración y encontré que la solución que utilizan es inicializar MapFragment en onCreate() y obtener la referencia a GoogleMap en onResume() , después de onCreateView() llamado a onCreateView() .

Necesito obtener la referencia a GoogleMap justo después de la inicialización de MapFragment, porque quiero que los usuarios puedan mostrar u ocultar el mapa con un botón. Sé que una posible solución sería crear el mapa al inicio como se dijo anteriormente y simplemente configurar su visibilidad, pero quiero que el mapa esté desactivado por defecto para que no tome ancho de banda del usuario si no se lo piden explícitamente para ello.

Intenté con MapsInitializer , pero tampoco funciona. Estoy como atrapado. ¿Algunas ideas? Aquí está mi código de prueba hasta el momento:

 public class ParadaInfoFragment extends BaseDBFragment { // BaseDBFragment is just a SherlockFragment with custom utility methods. private static final String MAP_FRAGMENT_TAG = "map"; private GoogleMap mMap; private SupportMapFragment mMapFragment; private TextView mToggleMapa; private boolean isMapVisible = false; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_parada_info, container, false); mToggleMapa = (TextView) v.findViewById(R.id.parada_info_map_button); return v; } @Override public void onStart() { super.onStart(); mToggleMapa.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!isMapVisible) { openMap(); } else { closeMap(); } isMapVisible = !isMapVisible; } }); } private void openMap() { // Creates initial configuration for the map GoogleMapOptions options = new GoogleMapOptions().camera(CameraPosition.fromLatLngZoom(new LatLng(37.4005502611301, -5.98233461380005), 16)) .compassEnabled(false).mapType(GoogleMap.MAP_TYPE_NORMAL).rotateGesturesEnabled(false).scrollGesturesEnabled(false).tiltGesturesEnabled(false) .zoomControlsEnabled(false).zoomGesturesEnabled(false); // Modified from the sample code: // It isn't possible to set a fragment's id programmatically so we set a // tag instead and search for it using that. mMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentByTag(MAP_FRAGMENT_TAG); // We only create a fragment if it doesn't already exist. if (mMapFragment == null) { // To programmatically add the map, we first create a // SupportMapFragment. mMapFragment = SupportMapFragment.newInstance(options); // Then we add it using a FragmentTransaction. FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.parada_info_map_container, mMapFragment, MAP_FRAGMENT_TAG); fragmentTransaction.commit(); } // We can't be guaranteed that the map is available because Google Play // services might not be available. setUpMapIfNeeded(); //XXX Here, getMap() returns null so the Marker can't be added // The map is shown with the previous options. } private void closeMap() { FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction(); fragmentTransaction.remove(mMapFragment); fragmentTransaction.commit(); } 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 = mMapFragment.getMap(); // Check if we were successful in obtaining the map. if (mMap != null) { mMap.addMarker(new MarkerOptions().position(new LatLng(37.4005502611301, -5.98233461380005)).title("Marker")); } } } } 

Gracias

El bueno de AnderWebs me dio una respuesta en Google+, pero él es demasiado laz … emm ocupado para escribir aquí de nuevo, así que aquí está la versión corta: Extienda la clase MapFragment y anule el método onCreateView() . Una vez hecho este método, podemos obtener una referencia no nula de ese objeto GoogleMap .

Esta es mi solución particular:

 public class MiniMapFragment extends SupportMapFragment { private LatLng mPosFija; public MiniMapFragment() { super(); } public static MiniMapFragment newInstance(LatLng posicion){ MiniMapFragment frag = new MiniMapFragment(); frag.mPosFija = posicion; return frag; } @Override public View onCreateView(LayoutInflater arg0, ViewGroup arg1, Bundle arg2) { View v = super.onCreateView(arg0, arg1, arg2); initMap(); return v; } private void initMap(){ UiSettings settings = getMap().getUiSettings(); settings.setAllGesturesEnabled(false); settings.setMyLocationButtonEnabled(false); getMap().moveCamera(CameraUpdateFactory.newLatLngZoom(mPosFija,16)); getMap().addMarker(new MarkerOptions().position(mPosFija).icon(BitmapDescriptorFactory.fromResource(R.drawable.marker))); } } 

Ahora en la clase anterior de Fragment hago

 mMapFragment = MiniMapFragment.newInstance(new LatLng(37.4005502611301, -5.98233461380005)); 

Quizás todavía no sea perfecto, porque la pantalla parpadea cuando se muestra el mapa. Pero no estoy seguro de si el problema es por esto u otra cosa.

Gracias, encontré esto muy útil. Estoy publicando mi solución ligeramente modificada, ya que fue más limpio para mí decirle al Fragmento padre cuando el mapa estaba listo. Este método también funciona con un ciclo saveInstanceState / restreInstanceState.

 public class CustomMapFragment extends SupportMapFragment { private static final String LOG_TAG = "CustomMapFragment"; public CustomMapFragment() { super(); } public static CustomMapFragment newInstance() { CustomMapFragment fragment = new CustomMapFragment(); return fragment; } @Override public View onCreateView(LayoutInflater arg0, ViewGroup arg1, Bundle arg2) { View v = super.onCreateView(arg0, arg1, arg2); Fragment fragment = getParentFragment(); if (fragment != null && fragment instanceof OnMapReadyListener) { ((OnMapReadyListener) fragment).onMapReady(); } return v; } /** * Listener interface to tell when the map is ready */ public static interface OnMapReadyListener { void onMapReady(); } } 

Para usar como un Fragmento nested: –

 public class ParentFragment extends Fragment implements OnMapReadyListener { ... mMapFragment = CustomMapFragment.newInstance(); getChildFragmentManager().beginTransaction().replace(R.id.mapContainer, mMapFragment).commit(); @Override public void onMapReady() { mMap = mMapFragment.getMap(); } ... } 

Espero que ayude a alguien.

Aquí está mi solución a esto, me inspiré en el código publicado anteriormente y lo limpié. También agregué los métodos estáticos con y sin los parámetros de GoogleMapOptions.

 public class GoogleMapFragment extends SupportMapFragment { private static final String SUPPORT_MAP_BUNDLE_KEY = "MapOptions"; public static interface OnGoogleMapFragmentListener { void onMapReady(GoogleMap map); } public static GoogleMapFragment newInstance() { return new GoogleMapFragment(); } public static GoogleMapFragment newInstance(GoogleMapOptions options) { Bundle arguments = new Bundle(); arguments.putParcelable(SUPPORT_MAP_BUNDLE_KEY, options); GoogleMapFragment fragment = new GoogleMapFragment(); fragment.setArguments(arguments); return fragment; } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mCallback = (OnGoogleMapFragmentListener) getActivity(); } catch (ClassCastException e) { throw new ClassCastException(getActivity().getClass().getName() + " must implement OnGoogleMapFragmentListener"); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = super.onCreateView(inflater, container, savedInstanceState); if (mCallback != null) { mCallback.onMapReady(getMap()); } return view; } private OnGoogleMapFragmentListener mCallback; } 

El patrón de uso es el siguiente:

 public class MyMapActivity implements OnGoogleMapFragmentListener { ... @Override public void onMapReady(GoogleMap map) { mUIGoogleMap = map; ... } ... private GoogleMap mUIGoogleMap; } 

No es necesario recortar SupportMapFragment , puede hacerlo directamente utilizando la siguiente pieza de código.

 FragmentManager fm = getSupportFragmentManager(); // getChildFragmentManager inside fragments. CameraPosition cp = new CameraPosition.Builder() .target(initialLatLng) // your initial co-ordinates here. like, LatLng initialLatLng .zoom(zoom_level) .build(); SupportMapFragment mapFragment = SupportMapFragment.newInstance(new GoogleMapOptions().camera(cp)); fm.beginTransaction().replace(R.id.rl_map, mapFragment).commit(); 

Agregue este fragmento de código para el layout

  

Esto cargará GoogleMap en una Location particular directamente, es decir, initialLatLng.