web-dev-qa-db-fra.com

Initialisez MapFragment par programmation avec Maps API v2

J'essaie d'ajouter un MapFragment à mon fragment actuel. L'utilisation de fragments imbriqués est limitée aux FragmentTransactions, vous ne pouvez pas utiliser la balise xml dans votre mise en page. De plus, je veux qu'il soit ajouté au fragment principal lorsque l'utilisateur appuie sur un bouton. Donc, je crée le MapFragment par programmation avec getInstance() lorsque l'utilisateur appuie sur ce bouton et l'ajoute au bon endroit. Il est affiché correctement, jusqu'ici tout va bien.

Le problème est qu'après avoir attaché le MapFragment, j'ai besoin d'obtenir une référence à GoogleMappour placer un marqueur, mais la méthode getMap() renvoie null (car le fragment onCreateView() n'a pas encore été appelé).

J'ai regardé l'exemple de code de démonstration et j'ai trouvé que la solution qu'ils utilisaient était d'initialiser le MapFragment dans onCreate() et d'obtenir la référence à GoogleMap dans onResume(), après l'appel de onCreateView().

J'ai besoin d'obtenir la référence à GoogleMap juste après l'initialisation de MapFragment, car je veux que les utilisateurs puissent afficher ou masquer la carte avec un bouton. Je sais qu'une solution possible serait de créer la carte au début comme indiqué ci-dessus et de définir simplement sa visibilité, mais je veux que la carte soit désactivée par défaut afin de ne pas prendre la bande passante de l'utilisateur s'il ne le demande pas explicitement. pour ça.

J'ai essayé avec le MapsInitializer, mais ça ne marche pas non plus. Je suis un peu coincé. Des idées? Voici mon code de test jusqu'à présent:

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"));
        }
    }
}
}

Merci

48
Sloy

Le bon AnderWebs m'a donné une réponse dans Google + mais il est trop paresseux .... emm occupé à l'écrire ici encore, alors voici la version courte: étendez la classe MapFragment et remplacer la méthode onCreateView(). Une fois cette méthode terminée, nous pouvons obtenir une référence non nulle à l'objet que GoogleMap.

Voici ma solution particulière:

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)));
    }
}

Maintenant, dans la classe Fragment précédente, je fais

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

Peut-être que ce n'est pas encore parfait, car l'écran clignote lors de l'affichage de la carte. Mais je ne sais pas si le problème est dû à cela ou à autre chose.

53
Sloy

Merci, j'ai trouvé cela très utile. Je publie ma solution légèrement modifiée, car il était plus propre pour moi de dire au fragment parent lorsque la carte était prête. Cette méthode fonctionne également avec un cycle saveInstanceState/restoreInstanceState.

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();
    }
}

Pour utiliser comme fragment imbriqué: -

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();
    }
    ...
}

J'espère que cela aide quelqu'un.

25
Ryan

Voici ma solution à cela, je me suis inspiré du code précédemment publié et l'ai nettoyé. J'ai également ajouté les méthodes statiques avec et sans les paramètres 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;
}

Le modèle d'utilisation est le suivant:

public class MyMapActivity implements OnGoogleMapFragmentListener {

    ...

    @Override
    public void onMapReady(GoogleMap map) {
        mUIGoogleMap = map;

        ...

    }

    ...

    private GoogleMap mUIGoogleMap;
}
14
Matteo Giaccone

Pas besoin de personnaliser SupportMapFragment vous pouvez le faire directement en utilisant le code suivant,

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();

Ajoutez ce morceau de code pour layout

<RelativeLayout
       Android:id="@+id/rl_map"
       Android:layout_width="fill_parent"
       Android:layout_height="fill_parent" />

Cela chargera GoogleMap dans un Location particulier, c'est-à-dire initialLatLng.

3
Jaydipsinh Zala