1. Введение
В то время как стандартные функции Карт Google невероятно полезны, иногда вам захочется сделать что-то еще. К счастью, Google создал библиотеку с открытым исходным кодом, содержащую набор утилит, которые разработчики Android могут использовать для улучшения своих приложений с помощью улучшенных карт.
В этом руководстве вы узнаете, как использовать эту служебную библиотеку для добавления визуализаций тепловых карт для ваших данных, кластеризации большого количества маркеров для более удобного просмотра и использования различных служебных методов для работы со сферической природой Земли или рисования маршрутов на дорогах. ,
Исходные файлы для этого урока можно найти на GitHub .
2. Настройка
В первом уроке из этой серии я рассказал, как настроить проект с помощью консоли разработчика Google и добавить ключ API в свой манифест. Для этого урока вам нужно получить ключ API и настроить ваш проект с манифестом, как описано там.
Затем откройте build.gradle и добавьте две новые зависимости: одну для Play Services, чтобы использовать Google Maps, а другую — для библиотеки Google Maps Utils.
1
2
|
compile ‘com.google.android.gms:play-services-maps:7.8.0’
compile ‘com.google.maps.android:android-maps-utils:0.4’
|
Следует отметить, что технически библиотека Google Maps Utils все еще находится на стадии бета-тестирования, хотя она была доступна в течение последних двух лет. После того, как вы импортировали эти библиотеки и синхронизировали проект, вам необходимо обновить файл макета для MainActivity.java, чтобы он использовал пользовательский фрагмент, показанный ниже.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<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» android:paddingLeft=»@dimen/activity_horizontal_margin»
android:paddingRight=»@dimen/activity_horizontal_margin»
android:paddingTop=»@dimen/activity_vertical_margin»
android:paddingBottom=»@dimen/activity_vertical_margin» tools:context=».MainActivity»>
<fragment
android:id=»@+id/list_fragment»
android:layout_width=»match_parent»
android:layout_height=»match_parent»
android:name=»com.tutsplus.mapsdemo.fragment.UtilsListFragment» />
</RelativeLayout>
|
Затем создайте класс UtilsListFragment
который используется выше, чтобы он отображал простой список элементов, представляющих различные части библиотеки, о которых вы узнаете в этом руководстве.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class UtilsListFragment extends ListFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayAdapter<String> adapter = new ArrayAdapter<String>( getActivity(), android.R.layout.simple_list_item_1 );
String[] items = getResources().getStringArray( R.array.list_items );
adapter.addAll( new ArrayList( Arrays.asList(items) ) );
setListAdapter( adapter );
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
String item = ( (TextView) v ).getText().toString();
if( getString( R.string.item_clustering ).equalsIgnoreCase( item ) ) {
startActivity( new Intent( getActivity(), ClusterMarkerActivity.class ) );
} else if( getString( R.string.item_heat_map ).equalsIgnoreCase( item ) ) {
startActivity( new Intent( getActivity(), HeatMapActivity.class ) );
} else if( getString( R.string.item_polylines ).equalsIgnoreCase( item ) ) {
startActivity( new Intent( getActivity(), PolylineActivity.class ) );
} else if( getString( R.string.item_spherical_geometry ).equalsIgnoreCase( item ) ) {
startActivity( new Intent( getActivity(), SphericalGeometryActivity.class ) );
}
}
}
|
Каждая из строк определяется и помещается в string-array
для единообразия.
01
02
03
04
05
06
07
08
09
10
11
|
<string name=»item_clustering»>Clustering</string>
<string name=»item_heat_map»>Heat Map</string>
<string name=»item_polylines»>Polyline Decoding</string>
<string name=»item_spherical_geometry»>Spherical Geometry Utils</string>
<string-array name=»list_items»>
<item>@string/item_clustering</item>
<item>@string/item_heat_map</item>
<item>@string/item_polylines</item>
<item>@string/item_spherical_geometry</item>
</string-array>
|
Как только ваш список станет доступен, вам нужно создать BaseMapActivity.java , который обрабатывает все настройки, относящиеся к общей карте, для каждого из примеров действий, которые вы будете строить. Это действие инициализирует GoogleMap
и увеличивает камеру в указанной области. В данном случае этот район — город Денвер в штате Колорадо, США. Все в этом классе должно выглядеть знакомым из последних двух статей этой серии.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
public abstract class BaseMapActivity extends AppCompatActivity {
protected LatLng mCenterLocation = new LatLng( 39.7392, -104.9903 );
protected GoogleMap mGoogleMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView( getMapLayoutId() );
initMapIfNecessary();
}
@Override
protected void onResume() {
super.onResume();
initMapIfNecessary();
}
protected void initMapIfNecessary() {
if( mGoogleMap != null ) {
return;
}
mGoogleMap = ( (MapFragment) getFragmentManager().findFragmentById( R.id.map ) ).getMap();
initMapSettings();
initCamera();
}
protected void initCamera() {
CameraPosition position = CameraPosition.builder()
.target( mCenterLocation )
.zoom( getInitialMapZoomLevel() )
.build();
mGoogleMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), null);
}
protected int getMapLayoutId() {
return R.layout.activity_map;
}
protected float getInitialMapZoomLevel() {
return 12.0f;
}
protected abstract void initMapSettings();
}
|
Теперь, когда у вас есть начальный проект, вы можете перейти к следующему разделу, в котором вы создадите новое действие для каждой утилиты, которую мы рассмотрим в этом руководстве.
3. Тепловые карты
Тепловые карты являются отличным способом визуального представления концентрации точек данных на карте. Библиотека Google Maps Utils позволяет легко добавлять их в приложение. Для начала создайте новый BaseMapActivity
именем HeatMapActivity
и добавьте его в файл AndroidManifest.xml . В верхней части этого класса объявите HeatmapTileProvider
который мы будем использовать для создания наложения карты.
1
|
private HeatmapTileProvider mProvider;
|
В BaseMapActivity
метод с именем initMapSettings
который позволяет добавлять настройки на карту. Для этого Activity
вам нужно переопределить этот метод, чтобы получить ArrayList
объектов LatLng
который затем используется для создания объекта HeatmapTileProvider
.
У провайдера есть различные методы, которые можно использовать для изменения внешнего вида вашей тепловой карты, такие как цвета градиента, радиус для каждой точки и вес каждой точки. После того, как ваш провайдер построен, вы можете создать тепловую карту TileOverlay
и применить ее к своей карте.
1
2
3
4
5
6
7
|
@Override
protected void initMapSettings() {
ArrayList<LatLng> locations = generateLocations();
mProvider = new HeatmapTileProvider.Builder().data( locations ).build();
mProvider.setRadius( HeatmapTileProvider.DEFAULT_RADIUS );
mGoogleMap.addTileOverlay(new TileOverlayOptions().tileProvider(mProvider));
}
|
В приведенной выше реализации initMapSettings
generateLocations
является вспомогательным методом, который генерирует 1000 позиций LatLng
вокруг LatLng
центральной карты.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
private ArrayList<LatLng> generateLocations() {
ArrayList<LatLng> locations = new ArrayList<LatLng>();
double lat;
double lng;
Random generator = new Random();
for( int i = 0; i < 1000; i++ ) {
lat = generator.nextDouble() / 3;
lng = generator.nextDouble() / 3;
if( generator.nextBoolean() ) {
lat = -lat;
}
if( generator.nextBoolean() ) {
lng = -lng;
}
locations.add(new LatLng(mCenterLocation.latitude + lat, mCenterLocation.longitude + lng));
}
return locations;
}
|
initMapSettings
реализацию initMapSettings
и generateLocations
, вы можете запустить свое приложение и щелкнуть по разделу тепловой карты, чтобы увидеть его в действии.
4. Кластерные маркеры
Когда на карте много точек данных, она может загромождаться очень быстро при уменьшении масштаба. Не только это, но и одновременное отображение слишком большого количества маркеров может привести к значительному замедлению работы некоторых устройств.
Чтобы облегчить некоторые проблемы, вызванные этими проблемами, вы можете использовать библиотеку Google Maps Utils, чтобы анимировать маркеры в кластеры. Первое, что вам нужно сделать, это создать новый объект модели, который реализует интерфейс ClusterItem
. Эта модель должна реализовать метод getPosition
из интерфейса ClusterItem
, чтобы вернуть действительный объект LatLng
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public class ClusterMarkerLocation implements ClusterItem {
private LatLng position;
public ClusterMarkerLocation( LatLng latLng ) {
position = latLng;
}
@Override
public LatLng getPosition() {
return position;
}
public void setPosition( LatLng position ) {
this.position = position;
}
}
|
ClusterMarkerActivity
модель, вы можете создать новый Activity
под названием ClusterMarkerActivity
и добавить его в свой манифест. Когда вы инициализируете свою карту, вам нужно создать ClusterManager
, связать его с GoogleMap
и добавить свои позиции LatLng
как ClusterMarkerLocations
в ClusterManager
чтобы утилита ClusterManager
знать, что кластеризовать. Посмотрите на реализацию initMarkers
чтобы лучше понять, как это работает.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
private void initMarkers() {
ClusterManager<ClusterMarkerLocation> clusterManager = new ClusterManager<ClusterMarkerLocation>( this, mGoogleMap );
mGoogleMap.setOnCameraChangeListener(clusterManager);
double lat;
double lng;
Random generator = new Random();
for( int i = 0; i < 1000; i++ ) {
lat = generator.nextDouble() / 3;
lng = generator.nextDouble() / 3;
if( generator.nextBoolean() ) {
lat = -lat;
}
if( generator.nextBoolean() ) {
lng = -lng;
}
clusterManager.addItem( new ClusterMarkerLocation( new LatLng( mCenterLocation.latitude + lat, mCenterLocation.longitude + lng ) ) );
}
}
|
В этом примере мы создаем 1000 случайных точек для отображения и добавляем их на карту. Библиотека Google Maps Utils обрабатывает все остальное для нас.
5. Другие утилиты
В дополнение к двум последним элементам библиотека Google Maps Utils содержит множество полезных утилит. Если у вас есть много разных точек, которые составляют маршрут, вы можете закодировать их как полилинию, а затем добавить эту полилинию к вашей карте, используя PolyUtil
. Это покажет путь между каждой из точек на карте.
01
02
03
04
05
06
07
08
09
10
11
|
public class PolylineActivity extends BaseMapActivity {
private static final String polyline = «gsqqFxxu_SyRlTys@npAkhAzY{MsVc`AuHwbB}Lil@}[goCqGe|BnUa`A~MkbG?eq@hRq}@_N}vKdB»;
@Override
protected void initMapSettings() {
List<LatLng> decodedPath = PolyUtil.decode(polyline);
mGoogleMap.addPolyline(new PolylineOptions().addAll(decodedPath));
}
}
|
В дополнение к PolyUtil
, Google добавил SphericalUtil
который можно использовать для измерения расстояний или определения геометрии вдоль поверхности сферы. Если вы хотите найти расстояние между двумя точками на карте, вы можете вызвать SphericalUtil.computeDistanceBetween( LatLng position1, LatLng position2 )
чтобы получить double
расстояние в метрах. Если вы хотите найти заголовок между двумя точками, вы можете вызвать SphericalUtil.computeHeading( LatLng point1, LatLng point2 )
.
В связи с этим еще один служебный метод в классе SpericalUtil
позволяет вам находить точку в определенном направлении и на расстоянии. Я рекомендую просмотреть документацию, чтобы узнать больше о классе SpericalUtil
.
Вывод
В этом руководстве вы только что коснулись библиотеки Google Maps Utils и всего, что она может предложить. Другие функции, которые он может добавить в ваше приложение, включают добавление наложений для данных KML, создание пользовательских маркеров и вспомогательных методов для работы с GeoJSON.
К счастью, Google открыл все библиотеки, поэтому вы можете найти исходный код и демонстрационный код библиотеки на GitHub . Изучив последние три части этой серии, вы должны чувствовать себя достаточно комфортно с Картами Google, чтобы добавить их в свои собственные приложения, чтобы обогатить пользовательский опыт и создавать отличные приложения.