How to Put Google Maps V2 on a Fragment Using Viewpager

How to put Google Maps V2 on a Fragment using ViewPager

By using this code we can setup MapView anywhere, inside any ViewPager or Fragment or Activity.

In the latest update of Google for Maps, only MapView is supported for fragments. MapFragment & SupportMapFragment didn't work for me.

Setting up the layout for showing the map in the file 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>

Now, we setup the Java class for showing the map in the file 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();
}
}

Finally you need to get the API Key for your app by registering your app at Google Cloud Console. Register your app as Native Android App.

Loading Android Google Map fragment managed by ViewPager

In your sole_map.xml you must add a MapView, let's say something like this:

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.maps.MapView
android:id="@+id/soleViewMap"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

Then get it from your SoleMap fragment with the id view.findViewById(R.id.soleViewMap); This will return you a MapView, then you can do what you're doing now. It should look something like this:

public class SoleMap extends Fragment implements OnMapReadyCallback {

MapView gMapView;
GoogleMap gMap = null;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.sole_map, container, false);

gMapView = (MapView) view.findViewById(R.id.soleViewMap);
gMapView.getMapAsync(this);

return view;
}

@Override
public void onMapReady(GoogleMap map) {
gMap = map;
gMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
gMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new
LatLng(49.39,-124.83), 20));
}
}

Don't forget to associate your mapview with the fragment lifecycle calling the events onCreate, onLowMemory, onPause, onResume and onDestroy (hope not missing any of them), and call to MapsInitializer.initialize(getContext()); as well

Google Map not showing on tab fragment in ViewPager

The problem is that when you call getActivity().getFragmentManager(), you're getting the Activity's Fragment Manager.

Since you're using a nested MapFragment inside of a Fragment, you need to use getChildFragmentManager(): For example:

GoogleMap mapFragment = ((MapFragment) getChildFragmentManager()
.findFragmentById(R.id.map)).getMap();

So, replace this:

map = ((MapFragment) getActivity().getFragmentManager().findFragmentById(R.id.map))
.getMap();

With this:

map = ((MapFragment) getChildFragmentManager().findFragmentById(R.id.map))
.getMap();

However, while that would work, you would be better off having your Fragment extend MapFragment or SupportMapFragment, that way you wouldn't need to have nested Fragments, and you would avoid the potential of running into this problem.

Solution using TabLayout from the support library:

As ActionBar Tabs are deprecated, this is now the best way to implement tabs with a ViewPager. Notice this is done without use of a nested SupportMapFragment, and instead has the map Fragment extent SupportMapFragment:

MainActivity imports:

import android.content.Context;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.support.v4.app.FragmentManager;
import android.view.View;
import android.widget.TextView;

MainActivity class:

public class MainActivity extends AppCompatActivity {

@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 = (ViewPager) findViewById(R.id.viewpager);
PagerAdapter 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));
}
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();

if (id == R.id.action_settings) {
return true;
}

return super.onOptionsItemSelected(item);
}

class PagerAdapter extends FragmentPagerAdapter {

String tabTitles[] = new String[] { "Tab One", "Tab Two", "Tab Three", };
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 BlankFragment();
case 1:
return new BlankFragment();
case 2:
return new MapFragment();
}

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

}
}

The MapFragment, notice that it directly extends SupportMapFragment instead of having a nested SupportMapFragment inside it:

import android.util.Log;

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.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class MapFragment extends SupportMapFragment implements
OnMapReadyCallback {

private final LatLng HAMBURG = new LatLng(53.558, 9.927);
private final LatLng KIEL = new LatLng(53.551, 9.993);

private static final String ARG_SECTION_NUMBER = "section_number";

private GoogleMap mMap;
private Marker marker;

public MapFragment() {
}

@Override
public void onResume() {
super.onResume();

Log.d("MyMap", "onResume");
setUpMapIfNeeded();
}

private void setUpMapIfNeeded() {

if (mMap == null) {

Log.d("MyMap", "setUpMapIfNeeded");

getMapAsync(this);
}
}

@Override
public void onMapReady(GoogleMap googleMap) {
Log.d("MyMap", "onMapReady");
mMap = googleMap;
setUpMap();
}

private void setUpMap() {

mMap.setMyLocationEnabled(true);
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.getUiSettings().setMapToolbarEnabled(false);


mMap.setMyLocationEnabled(true);
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.getUiSettings().setMapToolbarEnabled(false);

Marker hamburg = mMap.addMarker(new MarkerOptions().position(HAMBURG)
.title("Hamburg"));
Marker kiel = mMap.addMarker(new MarkerOptions()
.position(KIEL)
.title("Kiel")
.snippet("Kiel is cool")
.icon(BitmapDescriptorFactory
.fromResource(R.mipmap.ic_launcher)));

mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(HAMBURG, 15));

mMap.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
}
}

layout xml for the Activity:

<RelativeLayout
android:id="@+id/main_layout"
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"
tools:context=".MainActivity">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="?attr/colorPrimary"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

<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="6dp"
app:tabTextColor="#d3d3d3"
app:tabSelectedTextColor="#ffffff"
app:tabIndicatorColor="#ff00ff"
android:minHeight="?attr/actionBarSize"
/>

<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_below="@id/tab_layout"/>

</RelativeLayout>

custom_tab.xml, which is the layout for each tab:

<?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:singleLine="true"
/>
</LinearLayout>

Gradle:

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile 'com.google.android.gms:play-services:7.0.0'
}

Result:

Sample Image

Add Google Maps API V2 in a fragment

Here is the code,

public class YourFragment extends Fragment {
// ...
static final LatLng HAMBURG = new LatLng(53.558, 9.927);
static final LatLng KIEL = new LatLng(53.551, 9.993);
private GoogleMap map;

public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

View v = inflater.inflate(R.layout.yourlayout, null, false);

map = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.map))
.getMap();

Marker hamburg = map.addMarker(new MarkerOptions().position(HAMBURG)
.title("Hamburg"));
Marker kiel = map.addMarker(new MarkerOptions()
.position(KIEL)
.title("Kiel")
.snippet("Kiel is cool")
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.ic_launcher)));

// Move the camera instantly to hamburg with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(HAMBURG, 15));

// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);

//...

return v;
}

Your layout,

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >

<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />

</RelativeLayout>

Make some changes in your manifest file also.Like,

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myapp.android.locationapi.maps"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="17" />

<permission
android:name="com.myapp.android.locationapi.maps.permission.MAPS_RECEIVE"
android:protectionLevel="signature" />

<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />

<uses-permission android:name="com.myapp.android.locationapi.maps.permission.MAPS_RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.myapp.android.locationapi.maps.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="your_apikey" />
</application>

</manifest>

ViewPager with Google Maps API v2: mysterious black view

I was able to stop the black surface being left behind after transition by placing another view with a transparent background on top of the ViewPager inside a FrameLayout:

<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >

<android.support.v4.view.ViewPager
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>

<!-- hack to fix ugly black artefact with maps v2 -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent" />

</FrameLayout>

Adding a Map into a fragment using ViewPager for Swipe Views

Looks like your code is copied from this answer.

However you skipped this part:

<?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" />

And did this:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.nathan.trackrun.FragmentMap"
android:background="#000000" >
<fragment
android:id="@+id/location_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</FrameLayout>

Use MapView instead of a fragment.

How can I get current location google map in a fragment using view pager?

You should use MapView here as well instead of MapFragment:

MapFragment mapFragment = (MapFragment) getFragmentManager()
.findFragmentById(R.id.googlemap);

mapFragment.getMapAsync(this);

Try this example below:

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

}

Layout:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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" />

</FrameLayout>

Inflate Exception in Google Map Fragment in ViewPager with TabLayout

Note: You cannot inflate a layout into a fragment when that layout
includes a <fragment>.

Nested fragments are only supported when added
to a fragment dynamically.

This will solve your problem,but note there can be better ones,

  • Keep a static view in your maps fragment
  • In onCreateView check the view is null , first time its gonna be null
  • If there is a view (after first time load) you need to remove that,so every time when fragment gets called its like the very first time
  • Then you can set your view(your my_location) to fragment so you won't get a nested fragment problem

Example:

 private static View view;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (view != null) {
ViewGroup viewGroupParent = (ViewGroup) view.getParent();
if (viewGroupParent != null)
viewGroupParent.removeView(view);
}
try {
view = inflater.inflate(R.layout.yourLayoutWithMap, container, false);
} catch (Exception e) {
// map is already there
}
return view;
}

Find intersting answers here



Related Topics



Leave a reply



Submit