Я пытаюсь добавить MapFragment в свой текущий фрагмент. Использование вложенных фрагментов ограничено FragmentTransactions, вы не можете использовать тег xml в своем макете.
Кроме того, я хочу, чтобы он был добавлен в основной фрагмент, когда пользователь нажимает кнопку. Итак, я создаю MapFragment программно с помощью getInstance()
, когда пользователь нажимает эту кнопку и добавляет ее в нужное место. Это показано правильно, насколько это хорошо.
Проблема заключается в том, что после присоединения MapFragment мне нужно получить ссылку на GoogleMap
, чтобы поместить маркер, но метод getMap()
возвращает значение null (в качестве фрагмента onCreateView()
hasn ' t еще называется).
Я просмотрел код примера demo, и я нашел, что решение, которое они используют, инициализирует MapFragment в onCreate()
и получает ссылку на GoogleMap в onResume()
, после того, как был вызван onCreateView()
.
Мне нужно получить ссылку на GoogleMap сразу после инициализации MapFragment, потому что я хочу, чтобы пользователи могли показывать или скрывать карту с помощью кнопки. Я знаю, что возможным решением было бы создать карту в начале, как указано выше, и просто отключить ее видимость, но я хочу, чтобы карта была отключена по умолчанию, поэтому она не принимает пропускную способность пользователя, если они явно не заданы для него.
Я попытался с MapsInitializer
, но не работает. Я как бы застрял. Есть идеи?
Вот мой тестовый код:
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 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"));
}
}
}
}
Спасибо
Ответ 1
Хороший AnderWebs дал мне ответ в Google+, но он слишком laz.... emm занят, чтобы написать его здесь снова, так что здесь это короткая версия:
Расширьте класс MapFragment
и переопределите метод onCreateView()
. После этого метода мы можем получить ненулевую ссылку на объект que GoogleMap
.
Это мое особое решение:
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)));
}
}
Теперь в предыдущем классе фрагментов я делаю
mMapFragment = MiniMapFragment.newInstance(new LatLng(37.4005502611301, -5.98233461380005));
Может быть, он еще не идеален, потому что экран отображается при показе карты. Но не уверен, что проблема из-за этого или чего-то еще.
Ответ 2
Спасибо, нашел это очень полезным. Я размещаю свое слегка измененное решение, так как мне было проще рассказать родительский фрагмент, когда карта была готова. Этот метод также работает с циклом 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();
}
}
Использовать в качестве вложенного фрагмента: -
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();
}
...
}
Надеюсь, что это поможет кому-то.
Ответ 3
Здесь мое решение этого, я взял вдохновение из ранее опубликованного кода и очистил его. Я также добавил статические методы с параметрами 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;
}
Шаблон использования выглядит следующим образом:
public class MyMapActivity implements OnGoogleMapFragmentListener {
...
@Override
public void onMapReady(GoogleMap map) {
mUIGoogleMap = map;
...
}
...
private GoogleMap mUIGoogleMap;
}
Ответ 4
Нет необходимости вырезать SupportMapFragment
, вы можете сделать это напрямую, используя следующий фрагмент кода,
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();
Добавьте этот фрагмент кода для layout
<RelativeLayout
android:id="@+id/rl_map"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
Это будет загружать GoogleMap
при определенном Location
непосредственно, то есть initialLatLng.