android MapView in Fragment

后端 未结 5 1335
小蘑菇
小蘑菇 2020-11-30 02:49

I want to have MapView inside my Fragment

This is my FragmentLayout xml file



        
相关标签:
5条回答
  • 2020-11-30 03:00

    Makes sure you are overriding or calling OnDestroyView as well as OnDestroy. Something like ...

        public override void OnDestroy()
        {            
            base.OnDestroy();
            MapView.OnDestroy();
            OnDestroyView();            
        }
    
        public override void OnDestroyView()
        {            
            base.OnDestroyView();
            mapReadyCallbackList.Clear();            
    }
    
    0 讨论(0)
  • 2020-11-30 03:04

    In case somebody is looking for a Kotlin version of MapView Fragment ;)

    class MapViewKotlinFragment : Fragment(), OnMapReadyCallback {
    
    private var mMap: MapView? = null
    
    override fun onSaveInstanceState(outState: Bundle?) {
        super.onSaveInstanceState(outState)
    
        mMap?.onSaveInstanceState(outState)
    }
    
    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater?.inflate(R.layout.fragment_map, container, false)
    
        mMap = view?.findViewById(R.id.mapViewPlaces) as MapView
        mMap?.onCreate(savedInstanceState)
        mMap?.getMapAsync(this)
    
        return view
    }
    
    override fun onResume() {
        super.onResume()
        mMap?.onResume()
    }
    
    override fun onPause() {
        super.onPause()
        mMap?.onPause()
    }
    
    override fun onStart() {
        super.onStart()
        mMap?.onStart()
    }
    
    override fun onStop() {
        super.onStop()
        mMap?.onStop()
    }
    
    override fun onDestroy() {
        super.onDestroy()
        mMap?.onDestroy()
    }
    
    override fun onLowMemory() {
        super.onLowMemory()
        mMap?.onLowMemory()
    }
    
    override fun onMapReady(googleMap: GoogleMap) {
        googleMap.addMarker(MarkerOptions().position(LatLng(0.0, 0.0)).title("Marker"))
    }
    
    0 讨论(0)
  • 2020-11-30 03:04

    Old post, but might help someone who is looking to implement maps inside the fragment. Below is the detailed example using kotlin:

    First, add the permission in AndroidManifest.xml file:

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    

    Then under the application tag add meta-data in AndroidManifest.xml file:

    <meta-data
             android:name="com.google.android.gms.version"
             android:value="@integer/google_play_services_version" />
    
    <meta-data
           android:name="com.google.android.geo.API_KEY"
           android:value="@string/map_api_key"/>
    
    <uses-library
               android:name="org.apache.http.legacy"
               android:required="false" />
    

    *To get api link visit: https://developers.google.com/maps/documentation/android-sdk/get-api-key

    Implement play services in build.gradle file:

    implementation "com.google.android.gms:play-services-location:15.0.1"
    implementation "com.google.android.gms:play-services-places:15.0.1"
    implementation 'com.google.android.libraries.places:places:2.3.0'
    

    Add pulgin: apply plugin: 'com.google.gms.google-services'

    Add maps fragment inside your fragment.xml file:

    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
              android:name="com.google.android.gms.maps.SupportMapFragment"
              android:id="@+id/map"
              android:layout_width="match_parent"
              android:layout_height="match_parent"/>
    

    In your fragment.kt file, implement OnMapReadyCallback. Initialize the google map using getMapAsync(). Below code will let you integrate the google map and point it to your current location.

    package "Your_Package_Name"
    
    import android.Manifest
    import android.content.ContentValues.TAG
    
    import android.content.DialogInterface
    
    import android.content.pm.PackageManager
    import android.location.Location
    import android.os.Bundle
    import androidx.core.app.ActivityCompat
    import androidx.fragment.app.Fragment
    
    import androidx.core.content.ContextCompat
    import androidx.appcompat.app.AlertDialog
    import android.util.Log
    
    import android.view.LayoutInflater
    import android.view.MenuItem
    import android.view.View
    import android.view.ViewGroup
    import android.widget.FrameLayout
    import android.widget.TextView
    import android.widget.Toast
    
    import com.example.utilitybox.R
    import com.google.android.gms.location.FusedLocationProviderClient
    
    import com.google.android.gms.maps.*
    import com.google.android.gms.maps.model.CameraPosition
    import com.google.android.gms.maps.model.LatLng
    import com.google.android.gms.maps.model.Marker
    import com.google.android.gms.maps.model.MarkerOptions
    import com.google.android.libraries.places.api.model.Place
    import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest
    import com.google.android.libraries.places.api.net.PlacesClient
    
    
    class FragmentHome : Fragment(), OnMapReadyCallback {
    
        private var v:View?=null
        private var locationPermissionGranted = false
        private var googleMap: GoogleMap?=null
        
        private  var fusedLocationProviderClient: FusedLocationProviderClient?=null
        private val defaultLocation = LatLng(-33.8523341, 151.2106085)
        private var cameraPosition: CameraPosition? = null
        private  var placesClient: PlacesClient?=null
    
     
        private var lastKnownLocation: Location? = null
        private var likelyPlaceNames: Array<String?> = arrayOfNulls(0)
        private var likelyPlaceAddresses: Array<String?> = arrayOfNulls(0)
        private var likelyPlaceAttributions: Array<List<*>?> = arrayOfNulls(0)
        private var likelyPlaceLatLngs: Array<LatLng?> = arrayOfNulls(0)
    
    
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            if (savedInstanceState != null) {
                lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION)
                cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION)
            }
    
           v = inflater.inflate(R.layout.fragment_fragment_home, container, false)
    
            if(getString(R.string.map_api_key).isEmpty()){
                Toast.makeText(activity, "Add your own API key in MapWithMarker/app/secure.properties as MAPS_API_KEY=YOUR_API_KEY", Toast.LENGTH_LONG).show()
            }
    
            val mapFragment = childFragmentManager.findFragmentById(R.id.map) as? SupportMapFragment
            mapFragment?.getMapAsync(this)
    
            getLocationPermission()
    
            return v
        }
    
        override fun onSaveInstanceState(outState: Bundle) {
            googleMap?.let { map ->
                outState.putParcelable(KEY_CAMERA_POSITION, map.cameraPosition)
                outState.putParcelable(KEY_LOCATION, lastKnownLocation)
            }
            super.onSaveInstanceState(outState)
        }
       override fun onOptionsItemSelected(item: MenuItem): Boolean {
            if (item.itemId == R.id.option_get_place) {
                showCurrentPlace()
            }
            return true
        }
        
        override fun onMapReady(googleMap: GoogleMap) {
            this.googleMap = googleMap
    
            this.googleMap?.setInfoWindowAdapter(object : GoogleMap.InfoWindowAdapter {
                
                override fun getInfoWindow(arg0: Marker): View? {
                    return null
                }
    
                override fun getInfoContents(marker: Marker): View {
                    
                    val infoWindow = layoutInflater.inflate(R.layout.custom_info_contents,
                        v?.findViewById(R.id.map), false)
                    val title = infoWindow.findViewById<TextView>(R.id.title)
                    title.text = marker.title
                    val snippet = infoWindow.findViewById<TextView>(R.id.snippet)
                    snippet.text = marker.snippet
                    return infoWindow
                }
            })
            
            getLocationPermission()
        
                updateLocationUI()
    
              
                getDeviceLocation()
    
             
            }
    
      
        private fun getLocationPermission() {
         
            if (ContextCompat.checkSelfPermission(this.requireContext(),
                    Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
                locationPermissionGranted = true
            } else {
                ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION)
            }
        }
       
        override fun onRequestPermissionsResult(requestCode: Int,
                                                permissions: Array<String>,
                                                grantResults: IntArray) {
            locationPermissionGranted = false
            when (requestCode) {
                PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION -> {
    
                  
                    if (grantResults.isNotEmpty() &&
                        grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        locationPermissionGranted = true
                    }
                }
            }
            updateLocationUI()
        }
    
        private fun showCurrentPlace() {
            if (googleMap == null) {
                return
            }
            if (locationPermissionGranted) {
                
                val placeFields = listOf(Place.Field.NAME, Place.Field.ADDRESS, Place.Field.LAT_LNG)
    
               
                val request = FindCurrentPlaceRequest.newInstance(placeFields)
    
                
                val placeResult = placesClient?.findCurrentPlace(request)
                placeResult?.addOnCompleteListener { task ->
                    if (task.isSuccessful && task.result != null) {
                        val likelyPlaces = task.result
    
                       
                        val count = if (likelyPlaces != null && likelyPlaces.placeLikelihoods.size < M_MAX_ENTRIES) {
                            likelyPlaces.placeLikelihoods.size
                        } else {
                            M_MAX_ENTRIES
                        }
                        var i = 0
                        likelyPlaceNames = arrayOfNulls(count)
                        likelyPlaceAddresses = arrayOfNulls(count)
                        likelyPlaceAttributions = arrayOfNulls<List<*>?>(count)
                        likelyPlaceLatLngs = arrayOfNulls(count)
                        for (placeLikelihood in likelyPlaces?.placeLikelihoods ?: emptyList()) {
                           
                            likelyPlaceNames[i] = placeLikelihood.place.name
                            likelyPlaceAddresses[i] = placeLikelihood.place.address
                            likelyPlaceAttributions[i] = placeLikelihood.place.attributions
                            likelyPlaceLatLngs[i] = placeLikelihood.place.latLng
                            i++
                            if (i > count - 1) {
                                break
                            }
                        }
    
                     
                        openPlacesDialog()
                    } else {
                        Log.e(TAG, "Exception: %s", task.exception)
                    }
                }
            } else {
                
                Log.i(TAG, "The user did not grant location permission.")
    
              
                googleMap?.addMarker(MarkerOptions()
                    .title(getString(R.string.default_info_title))
                    .position(defaultLocation)
                    .snippet(getString(R.string.default_info_snippet)))
    
               
                getLocationPermission()
            }
        }
       
        private fun updateLocationUI() {
            if (googleMap == null) {
                return
            }
            try {
                if (locationPermissionGranted) {
                    googleMap?.isMyLocationEnabled = true
                    googleMap?.uiSettings?.isMyLocationButtonEnabled = true
                } else {
                    googleMap?.isMyLocationEnabled = false
                    googleMap?.uiSettings?.isMyLocationButtonEnabled = false
                    lastKnownLocation = null
                    getLocationPermission()
                }
            } catch (e: SecurityException) {
                Log.e("Exception: %s", e.message, e)
            }
        }
       
        private fun getDeviceLocation() {
         
            try {
                if (locationPermissionGranted) {
                    val locationResult = fusedLocationProviderClient?.lastLocation
                    if (locationResult != null) {
                        locationResult.addOnCompleteListener(this.requireActivity()) { task ->
                            if (task.isSuccessful) {
                                // Set the map's camera position to the current location of the device.
                                lastKnownLocation = task.result
                                if (lastKnownLocation != null) {
                                    googleMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(
                                        LatLng(lastKnownLocation!!.latitude,
                                            lastKnownLocation!!.longitude), DEFAULT_ZOOM.toFloat()))
                                }
                            } else {
                                Log.d(TAG, "Current location is null. Using defaults.")
                                Log.e(TAG, "Exception: %s", task.exception)
                                googleMap?.moveCamera(CameraUpdateFactory
                                    .newLatLngZoom(defaultLocation, DEFAULT_ZOOM.toFloat()))
                                googleMap?.uiSettings?.isMyLocationButtonEnabled = false
                            }
                        }
                    }
                }
            } catch (e: SecurityException) {
                Log.e("Exception: %s", e.message, e)
            }
        }
       
        private fun openPlacesDialog() {
           
            val listener = DialogInterface.OnClickListener { dialog, which -> 
                val markerLatLng = likelyPlaceLatLngs[which]
                var markerSnippet = likelyPlaceAddresses[which]
                if (likelyPlaceAttributions[which] != null) {
                    markerSnippet = """
                        $markerSnippet
                        ${likelyPlaceAttributions[which]}
                        """.trimIndent()
                }
    
                
                googleMap?.addMarker(MarkerOptions()
                    .title(likelyPlaceNames[which])
                    .position(markerLatLng!!)
                    .snippet(markerSnippet))
    
              
                googleMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,
                    DEFAULT_ZOOM.toFloat()))
            }
    
           
            AlertDialog.Builder(this.requireContext())
                .setTitle(R.string.pick_place)
                .setItems(likelyPlaceNames, listener)
                .show()
        }
        
    
        companion object {
    
            private const val DEFAULT_ZOOM = 15
            private const val PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1
    
           
            private const val KEY_CAMERA_POSITION = "camera_position"
            private const val KEY_LOCATION = "location"
           
           
            private const val M_MAX_ENTRIES = 5
        }
    }
    

    Once done add custom_info_contents.xml file in layout folder:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layoutDirection="locale"
                  android:orientation="vertical">
        <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:textColor="#ff000000"
                android:textStyle="bold" />
    
        <TextView
                android:id="@+id/snippet"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#ff7f7f7f" />
    </LinearLayout>
    

    Add below code in strings.xml file:

    <string name="map_api_key">YOUR_API_KEY</string>
    
        <!--Map strings-->
        <string name="title_activity_maps">Current Place Details</string>
        <string name="default_info_title">Default Location</string>
        <string name="default_info_snippet">No places found, because location permission is disabled.</string>
        <string name="option_get_place">Get place</string>
        <string name="pick_place">Choose a place</string>
    

    In menu folder create current_place_menu.xml file and add below code:

    <?xml version="1.0" encoding="utf-8"?><!--
         Copyright (C) 2016 The Android Open Source Project
         Licensed under the Apache License, Version 2.0 (the "License");
         you may not use this file except in compliance with the License.
         You may obtain a copy of the License at
              http://www.apache.org/licenses/LICENSE-2.0
         Unless required by applicable law or agreed to in writing, software
         distributed under the License is distributed on an "AS IS" BASIS,
         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         See the License for the specific language governing permissions and
         limitations under the License.
    -->
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto">
        <item
                android:id="@+id/option_get_place"
                android:title="@string/option_get_place"
                app:showAsAction="always"/>
    </menu>
    

    Hope this helps...

    0 讨论(0)
  • 2020-11-30 03:15

    Adding to M D's answer:

    From documentation:

    A GoogleMap must be acquired using getMapAsync(OnMapReadyCallback). The MapView automatically initializes the maps system and the view.

    According to this, the more correct way to initialize GoogleMap is using getMapAsync.

    Note that your class has to implement OnMapReadyCallback

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_map_page, container, false);
    
        mMapView = (MapView) v.findViewById(R.id.map_view);
        mMapView.onCreate(savedInstanceState);
        mMapView.getMapAsync(this); //this is important
    
        return v;
    }
    
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mGoogleMap = googleMap;
        mGoogleMap.getUiSettings().setZoomControlsEnabled(true);
        mGoogleMap.addMarker(new MarkerOptions().position(/*some location*/));
        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(/*some location*/, 10));
    }
    
    @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 onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mMapView.onSaveInstanceState(outState);
    }
    
    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mMapView.onLowMemory();
    }
    
    0 讨论(0)
  • 2020-11-30 03:19

    From Josh Holtz's example on GitHub:

    You should add MapView in your Layout like

     <com.google.android.gms.maps.MapView 
        android:id="@+id/mapview"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" />
    

    and implement your Fragment like

    public class SomeFragment extends Fragment {
    
    MapView mapView;
    GoogleMap map;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)          {
        View v = inflater.inflate(R.layout.some_layout, container, false);
    
        // Gets the MapView from the XML layout and creates it
        mapView = (MapView) v.findViewById(R.id.mapview);
        mapView.onCreate(savedInstanceState);
    
        // Gets to GoogleMap from the MapView and does initialization stuff
        map = mapView.getMap();
        map.getUiSettings().setMyLocationButtonEnabled(false);
        map.setMyLocationEnabled(true);
    
        // Needs to call MapsInitializer before doing any CameraUpdateFactory calls
        try {
            MapsInitializer.initialize(this.getActivity());
        } catch (GooglePlayServicesNotAvailableException e) {
            e.printStackTrace();
        }
    
        // Updates the location and zoom of the MapView
        CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(43.1, -87.9), 10);
        map.animateCamera(cameraUpdate);
    
        return v;
    }
    
    @Override
    public void onResume() {
        mapView.onResume();
        super.onResume();
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
     }
    
     @Override
     public void onLowMemory() {
        super.onLowMemory();
        mapView.onLowMemory();
      }
    
    }
    
    0 讨论(0)
提交回复
热议问题