Я пытаюсь сделать такую же раскладку вкладок в Play Store. Мне нужно отобразить макет вкладки, используя фрагменты и viewpager из androidhive. Однако я не могу реализовать на нем карты Google v2 . Я уже несколько часов искал в Интернете, но не могу найти учебника, как это сделать. Кто-нибудь, пожалуйста, покажите мне, как?
android
google-maps
android-fragments
Чонгбебс
источник
источник
Activity
и использовалсяFragment
однаждыgetChildFragmentManager()
.Ответы:
Используя этот код, мы можем настроить MapView где угодно, внутри любого ViewPager, фрагмента или действия.
В последнем обновлении Google for Maps для фрагментов поддерживается только MapView. MapFragment и SupportMapFragment не работает. Возможно, я ошибаюсь, но именно это я увидел после попытки реализовать MapFragment и SupportMapFragment.
Настройка макета для отображения карты в файле
location_fragment.xml
:<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <com.google.android.gms.maps.MapView android:id="@+id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
Теперь мы кодируем Java-класс для отображения карты в файле
MapViewFragment.java
:public class MapViewFragment extends Fragment { MapView mMapView; private GoogleMap googleMap; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.location_fragment, container, false); mMapView = (MapView) rootView.findViewById(R.id.mapView); mMapView.onCreate(savedInstanceState); mMapView.onResume(); // needed to get the map to display immediately try { MapsInitializer.initialize(getActivity().getApplicationContext()); } catch (Exception e) { e.printStackTrace(); } mMapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(GoogleMap mMap) { googleMap = mMap; // For showing a move to my location button googleMap.setMyLocationEnabled(true); // For dropping a marker at a point on the Map LatLng sydney = new LatLng(-34, 151); googleMap.addMarker(new MarkerOptions().position(sydney).title("Marker Title").snippet("Marker Description")); // For zooming automatically to the location of the marker CameraPosition cameraPosition = new CameraPosition.Builder().target(sydney).zoom(12).build(); googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); } }); return rootView; } @Override public void onResume() { super.onResume(); mMapView.onResume(); } @Override public void onPause() { super.onPause(); mMapView.onPause(); } @Override public void onDestroy() { super.onDestroy(); mMapView.onDestroy(); } @Override public void onLowMemory() { super.onLowMemory(); mMapView.onLowMemory(); } }
Наконец, вам нужно получить ключ API для своего приложения, зарегистрировав свое приложение в Google Cloud Console . Зарегистрируйте свое приложение как собственное приложение для Android.
источник
<uses-library android:name="com.google.android.maps" android:required="true" />
предназначен для карт V1, а не Maps V2. В будущем появятся устройства, в которых нетcom.google.android.maps
библиотеки микропрограмм, но которые вполне способны отображать карты Maps V2. Наличие этой строки в вашем манифесте предотвратит запуск на таких устройствах, и эта строка не требуется для использования Maps V2. Например, 17 проектов на github.com/commonsguy/cw-omnibus/tree/master/MapsV2 не имеют этого<uses-library>
элемента и работают нормально.java.lang.NullPointerException: Attempt to invoke interface method 'void com.google.maps.api.android.lib6.impl.bo.o()' on a null object reference
У меня работает следующий подход.
import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.MapView; import com.google.android.gms.maps.MapsInitializer; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; /** * A fragment that launches other parts of the demo application. */ public class MapFragment extends Fragment { MapView mMapView; private GoogleMap googleMap; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // inflat and return the layout View v = inflater.inflate(R.layout.fragment_location_info, container, false); mMapView = (MapView) v.findViewById(R.id.mapView); mMapView.onCreate(savedInstanceState); mMapView.onResume();// needed to get the map to display immediately try { MapsInitializer.initialize(getActivity().getApplicationContext()); } catch (Exception e) { e.printStackTrace(); } googleMap = mMapView.getMap(); // latitude and longitude double latitude = 17.385044; double longitude = 78.486671; // create marker MarkerOptions marker = new MarkerOptions().position( new LatLng(latitude, longitude)).title("Hello Maps"); // Changing marker icon marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_ROSE)); // adding marker googleMap.addMarker(marker); CameraPosition cameraPosition = new CameraPosition.Builder() .target(new LatLng(17.385044, 78.486671)).zoom(12).build(); googleMap.animateCamera(CameraUpdateFactory .newCameraPosition(cameraPosition)); // Perform any camera updates here return v; } @Override public void onResume() { super.onResume(); mMapView.onResume(); } @Override public void onPause() { super.onPause(); mMapView.onPause(); } @Override public void onDestroy() { super.onDestroy(); mMapView.onDestroy(); } @Override public void onLowMemory() { super.onLowMemory(); mMapView.onLowMemory(); } }
fragment_location_info.xml
<?xml version="1.0" encoding="utf-8"?> <com.google.android.gms.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" />
источник
java.lang.NullPointerException: IBitmapDescriptorFactory is not initialized
. Я думал, что try catch позаботится об этом. Кто-нибудь может мне помочь?mMapView
?getMap()
не рекомендуется. Вместо этого используйте getMapAsync и onMapReadyCallback: stackoverflow.com/a/31371953/4549776Вы можете использовать эту строку, если хотите использовать
GoogleMap
во фрагменте:<fragment android:id="@+id/map" android:layout_width="wrap_content" android:layout_height="match_parent" class="com.google.android.gms.maps.SupportMapFragment" />
GoogleMap mGoogleMap = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map)).getMap();
источник
Последние материалы с
getMapAsync
вместо устаревшего.1. проверьте манифест для
<meta-data android:name="com.google.android.geo.API_KEY" android:value="xxxxxxxxxxxxxxxxxxxxxxxxx"/>
Вы можете получить ключ API для своего приложения, зарегистрировав свое приложение по адресу
Google Cloud Console
. Зарегистрируйте свое приложение как собственное приложение для Android2. в макете фрагмента .xml добавьте FrameLayout (не фрагмент):
<FrameLayout android:layout_width="match_parent" android:layout_height="250dp" android:layout_weight="2" android:name="com.google.android.gms.maps.SupportMapFragment" android:id="@+id/mapwhere" />
или любой другой высоты
3. В onCreateView в вашем фрагменте
private SupportMapFragment mSupportMapFragment; mSupportMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.mapwhere); if (mSupportMapFragment == null) { FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); mSupportMapFragment = SupportMapFragment.newInstance(); fragmentTransaction.replace(R.id.mapwhere, mSupportMapFragment).commit(); } if (mSupportMapFragment != null) { mSupportMapFragment.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(GoogleMap googleMap) { if (googleMap != null) { googleMap.getUiSettings().setAllGesturesEnabled(true); -> marker_latlng // MAKE THIS WHATEVER YOU WANT CameraPosition cameraPosition = new CameraPosition.Builder().target(marker_latlng).zoom(15.0f).build(); CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition); googleMap.moveCamera(cameraUpdate); } } });
источник
<fragment
вместоFrameLayout
SupportMapFragment
вMapFragment
в деятельности, изменилсяFrameLayout
вfragment
в файле макета и и изменилcom.google.android.gms.maps.SupportMapFragment
вcom.google.android.gms.maps.MapFragment
нем отлично работает для меня. До этих изменений не работало. Может, это поможет другим ....вот что я сделал подробно:
Отсюда вы можете получить ключ API карты Google
альтернативный и простой способ
сначала войдите в свою учетную запись Google, посетите библиотеки Google и выберите Google Maps Android API
Зависимость найдена в действии карты по умолчанию студии android:
compile 'com.google.android.gms:play-services:10.0.1'
поместите свой ключ в файл mainifest android в приложении, как показано ниже
в AndroidMainifest.xml внесите следующие изменения:
// required permission <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> // google map api key put under/inside <application></application> // android:value="YOUR API KEY" <meta-data android:name="com.google.android.geo.API_KEY" android:value="AIzasdfasdf645asd4f847sad5f45asdf7845" />
Код фрагмента:
public class MainBranchFragment extends Fragment implements OnMapReadyCallback{ private GoogleMap mMap; public MainBranchFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view= inflater.inflate(R.layout.fragment_main_branch, container, false); SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.main_branch_map); mapFragment.getMapAsync(this); return view; } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; LatLng UCA = new LatLng(-34, 151); mMap.addMarker(new MarkerOptions().position(UCA).title("YOUR TITLE")).showInfoWindow(); mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(UCA,17)); } }
в вашем фрагменте xml:
<fragment android:id="@+id/main_branch_map" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.googlemap.googlemap.MapsActivity" />
источник
Что касается проблемы с получением,
NullPointerException
когда мы меняем вкладки в,FragmentTabHost
вам просто нужно добавить этот код в свой класс, который имеет расширениеTabHost
. Я имею в виду класс, в котором вы инициализируете вкладки. Это код:/**** Fix for error : Activity has been destroyed, when using Nested tabs * We are actually detaching this tab fragment from the `ChildFragmentManager` * so that when this inner tab is viewed back then the fragment is attached again****/ import java.lang.reflect.Field; @Override public void onDetach() { super.onDetach(); try { Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager"); childFragmentManager.setAccessible(true); childFragmentManager.set(this, null); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }
источник
public class DemoFragment extends Fragment { MapView mapView; GoogleMap map; LatLng CENTER = null; public LocationManager locationManager; double longitudeDouble; double latitudeDouble; String snippet; String title; Location location; String myAddress; String LocationId; String CityName; String imageURL; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub View view = inflater .inflate(R.layout.fragment_layout, container, false); mapView = (MapView) view.findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); setMapView(); } private void setMapView() { try { MapsInitializer.initialize(getActivity()); switch (GooglePlayServicesUtil .isGooglePlayServicesAvailable(getActivity())) { case ConnectionResult.SUCCESS: // Toast.makeText(getActivity(), "SUCCESS", Toast.LENGTH_SHORT) // .show(); // Gets to GoogleMap from the MapView and does initialization // stuff if (mapView != null) { locationManager = ((LocationManager) getActivity() .getSystemService(Context.LOCATION_SERVICE)); Boolean localBoolean = Boolean.valueOf(locationManager .isProviderEnabled("network")); if (localBoolean.booleanValue()) { CENTER = new LatLng(latitude, longitude); } else { } map = mapView.getMap(); if (map == null) { Log.d("", "Map Fragment Not Found or no Map in it!!"); } map.clear(); try { map.addMarker(new MarkerOptions().position(CENTER) .title(CityName).snippet("")); } catch (Exception e) { e.printStackTrace(); } map.setIndoorEnabled(true); map.setMyLocationEnabled(true); map.moveCamera(CameraUpdateFactory.zoomTo(5)); if (CENTER != null) { map.animateCamera( CameraUpdateFactory.newLatLng(CENTER), 1750, null); } // add circle CircleOptions circle = new CircleOptions(); circle.center(CENTER).fillColor(Color.BLUE).radius(10); map.addCircle(circle); map.setMapType(GoogleMap.MAP_TYPE_NORMAL); } break; case ConnectionResult.SERVICE_MISSING: break; case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED: break; default: } } catch (Exception e) { } }
в fragment_layout
<com.google.android.gms.maps.MapView android:id="@+id/mapView" android:layout_width="match_parent" android:layout_height="160dp" android:layout_marginRight="10dp" />
источник
Когда вы добавляете свою карту, используйте:
getChildFragmentManager().beginTransaction() .replace(R.id.menu_map_container, mapFragment, "f" + shabbatIndex).commit();
вместо
.add
и вместоgetFragmentManager
.источник
Я просто создаю MapActivity и раздуваю его до фрагмента. MapActivity.java:
package com.example.ahmedsamra.mansouratourguideapp; import android.support.v4.app.FragmentActivity; import android.os.Bundle; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; public class MapsActivity extends FragmentActivity implements OnMapReadyCallback { private GoogleMap mMap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_categories);//layout for container getSupportFragmentManager().beginTransaction() .replace(R.id.container, new MapFragment()) .commit(); // Obtain the SupportMapFragment and get notified when the map is ready to be used. SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); } /** * Manipulates the map once available. * This callback is triggered when the map is ready to be used. * This is where we can add markers or lines, add listeners or move the camera. In this case, * we just add a marker near Sydney, Australia. * If Google Play services is not installed on the device, the user will be prompted to install * it inside the SupportMapFragment. This method will only be triggered once the user has * installed Google Play services and returned to the app. */ @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; // Add a marker in Sydney and move the camera LatLng mansoura = new LatLng(31.037933, 31.381523); mMap.addMarker(new MarkerOptions().position(mansoura).title("Marker in mansoura")); mMap.moveCamera(CameraUpdateFactory.newLatLng(mansoura)); } }
activity_map.xml:
<fragment xmlns:android="http://schemas.android.com/apk/res/android" xmlns:map="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/map" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.ahmedsamra.mansouratourguideapp.MapsActivity" />
MapFragment.java:-
package com.example.ahmedsamra.mansouratourguideapp; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; /** * A simple {@link Fragment} subclass. */ public class MapFragment extends Fragment { public MapFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.activity_maps,container,false); return rootView; } }
источник
Это способ Котлина:
У
fragment_map.xml
вас должно быть:<?xml version="1.0" encoding="utf-8"?> <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" />
В вашем у
MapFragment.kt
вас должно быть:private fun setupMap() { (childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?)!!.getMapAsync(this) }
Звоните
setupMap()
вonCreateView
.источник
У меня есть обходной путь,
NullPointerException
когда вы удаляете фрагмент.DestoryView
Просто вставьте свой кодonStop()
неonDestoryView
. Работает нормально!@Override public void onStop() { super.onStop(); if (mMap != null) { MainActivity.fragmentManager.beginTransaction() .remove(MainActivity.fragmentManager.findFragmentById(R.id.location_map)).commit(); mMap = null; } }
источник
Согласно https://developer.android.com/about/versions/android-4.2.html#NestedFragments , вы можете использовать вложенные фрагменты для достижения этого, вызвав getChildFragmentManager (), если вы все еще хотите использовать фрагмент Google Maps вместо посмотреть внутри собственного фрагмента:
SupportMapFragment mapFragment = new SupportMapFragment(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction.add(R.id.content, mapFragment).commit();
где «контент» - это корневой макет в вашем фрагменте (предпочтительно FrameLayout). Преимущество использования фрагмента карты заключается в том, что в этом случае система автоматически управляет жизненным циклом карты.
Хотя в документации сказано: «Вы не можете раздуть макет во фрагмент, если этот макет включает <fragment>. Вложенные фрагменты поддерживаются только при динамическом добавлении к фрагменту», я каким-то образом успешно сделал это, и все работало нормально. Вот мой код:
В методе фрагмента onCreateView ():
View view = inflater.inflate(R.layout.layout_maps, container, false); SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(...);
В макете:
<fragment xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/map" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" />
Надеюсь, это поможет!
источник
Динамическое добавление фрагмента карты для просмотра пейджера:
Если вы ориентируетесь на приложение до уровня API 12, создайте экземпляр SupportedMapFragment и добавьте его в свой адаптер страницы просмотра.
SupportMapFragment supportMapFragment=SupportMapFragment.newInstance(); supportMapFragment.getMapAsync(this);
Уровень API 12 или выше поддерживает объекты MapFragment
MapFragment mMapFragment=MapFragment.newInstance(); mMapFragment.getMapAsync(this);
источник