How to get current location within a Google Maps Fragment in a ViewPager with TabLayout

前端 未结 1 1857
既然无缘
既然无缘 2020-12-04 00:49

I managed to implement a TabLayout. Within one of the tabs is a Google Maps Fragment. I want to ask permission to access the user\'s location and then place a marker on the

相关标签:
1条回答
  • 2020-12-04 01:33

    This is very close to my other answer here, however, that answer doesn't explain how to do it using a ViewPager with a TabLayout.

    First, the piece that sets this apart from the other answer, you'll need to keep a reference to the current Fragment in the FragmentPagerAdapter using the instantiateItem() override.

    Also, note that the onRequestPermissionsResult() method is needed here in the Activity in order to route the user's permission request response to the Fragment.

    Here is the full Activity code:

    public class MainActivity extends AppCompatActivity {
    
        ViewPager viewPager;
        PagerAdapter pagerAdapter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
    
            // Get the ViewPager and set it's PagerAdapter so that it can display items
            viewPager = (ViewPager) findViewById(R.id.viewpager);
            pagerAdapter = new PagerAdapter(getSupportFragmentManager(), MainActivity.this);
            viewPager.setAdapter(pagerAdapter);
    
            // Give the TabLayout the ViewPager
            TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
            tabLayout.setupWithViewPager(viewPager);
    
            // Iterate over all tabs and set the custom view
            for (int i = 0; i < tabLayout.getTabCount(); i++) {
                TabLayout.Tab tab = tabLayout.getTabAt(i);
                tab.setCustomView(pagerAdapter.getTabView(i));
            }
        }
    
        class PagerAdapter extends FragmentPagerAdapter {
    
            String tabTitles[] = new String[] { "Tab One", "Tab Two", "Tab Three", };
            public Fragment[] fragments = new Fragment[tabTitles.length];
            Context context;
    
            public PagerAdapter(FragmentManager fm, Context context) {
                super(fm);
                this.context = context;
            }
    
            @Override
            public int getCount() {
                return tabTitles.length;
            }
    
            @Override
            public Fragment getItem(int position) {
    
                switch (position) {
                    case 0:
                        return new MapFragment();
                    case 1:
                        return new BlankFragment();
                    case 2:
                        return new BlankFragment();
                }
    
                return null;
            }
    
            @Override
            public CharSequence getPageTitle(int position) {
                // Generate title based on item position
                return tabTitles[position];
            }
    
            public View getTabView(int position) {
                View tab = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_tab, null);
                TextView tv = (TextView) tab.findViewById(R.id.custom_text);
                tv.setText(tabTitles[position]);
                return tab;
            }
    
            //This populates your Fragment reference array:
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
                fragments[position]  = createdFragment;
                return createdFragment;
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode,
                                               String permissions[], int[] grantResults) {
            if (requestCode == MapFragment.MY_PERMISSIONS_REQUEST_LOCATION){
                MapFragment mapFragment = (MapFragment) pagerAdapter.fragments[0];
                if (mapFragment != null) {
                    mapFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
                }
            }
            else {
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    }
    

    activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context=".MainActivity">
    
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay"
            android:elevation="6dp">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                android:elevation="0dp" />
    
            <android.support.design.widget.TabLayout
                android:id="@+id/tab_layout"
                app:tabMode="fixed"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/toolbar"
                android:background="?attr/colorPrimary"
                android:elevation="0dp"
                app:tabTextColor="#d3d3d3"
                app:tabSelectedTextColor="#ffffff"
                app:tabIndicatorColor="#ff00ff"
                android:minHeight="?attr/actionBarSize"
                />
    
        </android.support.design.widget.AppBarLayout>
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="fill_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            />
    
    </android.support.design.widget.CoordinatorLayout>
    

    custom_tab.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/custom_text"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="?attr/selectableItemBackground"
            android:gravity="center"
            android:textSize="16dip"
            android:textColor="#ffffff"
            android:maxLines="1"
            />
    </LinearLayout>
    

    For the Map Fragment, use essentially the same code as the other answer:

    public class MapFragment extends SupportMapFragment
            implements OnMapReadyCallback,
            GoogleApiClient.ConnectionCallbacks,
            GoogleApiClient.OnConnectionFailedListener,
            LocationListener {
    
        GoogleMap mGoogleMap;
        LocationRequest mLocationRequest;
        GoogleApiClient mGoogleApiClient;
        Location mLastLocation;
        Marker mCurrLocationMarker;
    
        @Override
        public void onResume() {
            super.onResume();
    
            setUpMapIfNeeded();
        }
    
        private void setUpMapIfNeeded() {
    
            if (mGoogleMap == null) {
                getMapAsync(this);
            }
        }
        @Override
        public void onPause() {
            super.onPause();
    
            //stop location updates when Activity is no longer active
            if (mGoogleApiClient != null) {
                LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            }
        }
    
        @Override
        public void onMapReady(GoogleMap googleMap)
        {
            mGoogleMap=googleMap;
            mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
    
            //Initialize Google Play Services
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (ContextCompat.checkSelfPermission(getActivity(),
                        Manifest.permission.ACCESS_FINE_LOCATION)
                        == PackageManager.PERMISSION_GRANTED) {
                    //Location Permission already granted
                    buildGoogleApiClient();
                    mGoogleMap.setMyLocationEnabled(true);
                } else {
                    //Request Location Permission
                    checkLocationPermission();
                }
            }
            else {
                buildGoogleApiClient();
                mGoogleMap.setMyLocationEnabled(true);
            }
        }
    
        protected synchronized void buildGoogleApiClient() {
            mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .addApi(LocationServices.API)
                    .build();
            mGoogleApiClient.connect();
        }
    
        @Override
        public void onConnected(Bundle bundle) {
            mLocationRequest = new LocationRequest();
            mLocationRequest.setInterval(1000);
            mLocationRequest.setFastestInterval(1000);
            mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
            if (ContextCompat.checkSelfPermission(getActivity(),
                    Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
            }
        }
    
        @Override
        public void onConnectionSuspended(int i) {}
    
        @Override
        public void onConnectionFailed(ConnectionResult connectionResult) {}
    
        @Override
        public void onLocationChanged(Location location)
        {
            mLastLocation = location;
            if (mCurrLocationMarker != null) {
                mCurrLocationMarker.remove();
            }
    
            //Place current location marker
            LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
            MarkerOptions markerOptions = new MarkerOptions();
            markerOptions.position(latLng);
            markerOptions.title("Current Position");
            markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
            mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);
    
            //move map camera
            mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
            mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(11));
    
            //optionally, stop location updates if only current location is needed
            if (mGoogleApiClient != null) {
                LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            }
        }
    
        public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
        private void checkLocationPermission() {
            if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED) {
    
                // Should we show an explanation?
                if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
                        Manifest.permission.ACCESS_FINE_LOCATION)) {
    
                    // Show an explanation to the user *asynchronously* -- don't block
                    // this thread waiting for the user's response! After the user
                    // sees the explanation, try again to request the permission.
                    new AlertDialog.Builder(getActivity())
                            .setTitle("Location Permission Needed")
                            .setMessage("This app needs the Location permission, please accept to use location functionality")
                            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    //Prompt the user once explanation has been shown
                                    ActivityCompat.requestPermissions(getActivity(),
                                            new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                            MY_PERMISSIONS_REQUEST_LOCATION );
                                }
                            })
                            .create()
                            .show();
    
    
                } else {
                    // No explanation needed, we can request the permission.
                    ActivityCompat.requestPermissions(getActivity(),
                            new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                            MY_PERMISSIONS_REQUEST_LOCATION );
                }
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode,
                                               String permissions[], int[] grantResults) {
            switch (requestCode) {
                case MY_PERMISSIONS_REQUEST_LOCATION: {
                    // If request is cancelled, the result arrays are empty.
                    if (grantResults.length > 0
                            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    
                        // permission was granted, yay! Do the
                        // location-related task you need to do.
                        if (ContextCompat.checkSelfPermission(getActivity(),
                                Manifest.permission.ACCESS_FINE_LOCATION)
                                == PackageManager.PERMISSION_GRANTED) {
    
                            if (mGoogleApiClient == null) {
                                buildGoogleApiClient();
                            }
                            mGoogleMap.setMyLocationEnabled(true);
                        }
    
                    } else {
    
                        // permission denied, boo! Disable the
                        // functionality that depends on this permission.
                        Toast.makeText(getActivity(), "permission denied", Toast.LENGTH_LONG).show();
                    }
                    return;
                }
    
                // other 'case' lines to check for other
                // permissions this app might request
            }
        }
    
    }
    

    Result

    First, the location permission prompt:

    Once the user has accepted the permission at runtime, show the user's current location:

    0 讨论(0)
提交回复
热议问题