From 98d3e7b9e924ca41926f7095cf92c4bed91cbb5b Mon Sep 17 00:00:00 2001 From: tobrun Date: Thu, 6 Sep 2018 07:42:01 +0200 Subject: [PATCH] [markerview] - add initial markerview plugin --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 11 ++ .../markerview/MarkerViewActivity.java | 150 ++++++++++++++++++ app/src/main/res/layout/marker_view.xml | 26 +++ app/src/main/res/values/strings.xml | 3 + plugin-markerview/.gitignore | 1 + plugin-markerview/build.gradle | 47 ++++++ plugin-markerview/gradle.properties | 5 + plugin-markerview/proguard-rules.pro | 21 +++ .../src/main/AndroidManifest.xml | 2 + .../plugins/markerview/MarkerView.java | 83 ++++++++++ .../plugins/markerview/MarkerViewManager.java | 92 +++++++++++ settings.gradle | 1 + 13 files changed, 443 insertions(+) create mode 100644 app/src/main/java/com/mapbox/mapboxsdk/plugins/testapp/activity/markerview/MarkerViewActivity.java create mode 100644 app/src/main/res/layout/marker_view.xml create mode 100644 plugin-markerview/.gitignore create mode 100644 plugin-markerview/build.gradle create mode 100644 plugin-markerview/gradle.properties create mode 100644 plugin-markerview/proguard-rules.pro create mode 100644 plugin-markerview/src/main/AndroidManifest.xml create mode 100644 plugin-markerview/src/main/java/com/mapbox/mapboxsdk/plugins/markerview/MarkerView.java create mode 100644 plugin-markerview/src/main/java/com/mapbox/mapboxsdk/plugins/markerview/MarkerViewManager.java diff --git a/app/build.gradle b/app/build.gradle index e1d5ba240..76b8df73d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -120,6 +120,7 @@ dependencies { implementation project(':plugin-offline') implementation project(':plugin-localization') implementation project(':plugin-annotation') + implementation project(':plugin-markerview') } apply from: "${rootDir}/gradle/checkstyle.gradle" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7a01b5229..819d3c011 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -191,6 +191,17 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> + + + + { + mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(2)); + + markerViewManager = new MarkerViewManager(mapView, mapboxMap); + createCustomMarker(); + createRandomMarkers(); + + mapboxMap.addOnMapLongClickListener(MarkerViewActivity.this); + mapboxMap.addOnMapClickListener(MarkerViewActivity.this); + }); + } + + private void createCustomMarker() { + // create a custom animation marker view + final View customView = createCustomAnimationView(); + marker = new MarkerView(new LatLng(), customView); + markerViewManager.addMarker(marker); + } + + private View createCustomAnimationView() { + View customView = LayoutInflater.from(this).inflate(R.layout.marker_view, null); + customView.setLayoutParams(new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + View icon = customView.findViewById(R.id.imageview); + View animationView = customView.findViewById(R.id.animation_layout); + icon.setOnClickListener(v -> { + ValueAnimator anim = ValueAnimator.ofInt(animationView.getMeasuredWidth(), 350); + anim.setInterpolator(new AccelerateDecelerateInterpolator()); + anim.addUpdateListener(valueAnimator -> { + int val = (Integer) valueAnimator.getAnimatedValue(); + ViewGroup.LayoutParams layoutParams = animationView.getLayoutParams(); + layoutParams.width = val; + animationView.setLayoutParams(layoutParams); + }); + anim.setDuration(1250); + anim.start(); + }); + return customView; + } + + private void createRandomMarkers() { + for (int i = 0; i < 20; i++) { + final ImageView imageView = new ImageView(MarkerViewActivity.this); + imageView.setImageResource(R.drawable.ic_car); + imageView.setLayoutParams(new FrameLayout.LayoutParams(56, 56)); + MarkerView markerView = new MarkerView(createRandomLatLng(), imageView); + markerViewManager.addMarker(markerView); + } + } + + private LatLng createRandomLatLng() { + return new LatLng((random.nextDouble() * -180.0) + 90.0, + (random.nextDouble() * -360.0) + 180.0); + } + + @Override + public void onMapLongClick(@NonNull LatLng point) { + if (marker != null) { + markerViewManager.removeMarker(marker); + marker = null; + } + } + + @Override + public void onMapClick(@NonNull LatLng point) { + if (marker != null) { + marker.setLatLng(point); + } + } + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + markerViewManager.onDestroy(); + mapView.onDestroy(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } +} diff --git a/app/src/main/res/layout/marker_view.xml b/app/src/main/res/layout/marker_view.xml new file mode 100644 index 000000000..78c05662d --- /dev/null +++ b/app/src/main/res/layout/marker_view.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 08c2efcc3..0197b32f6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,6 +11,7 @@ Offline Localization Annotations + View synchronisation Traffic Plugin @@ -28,6 +29,7 @@ Offline Ui Components Location Fragment Symbol plugin + MarkerView plugin Add Traffic layers to any Mapbox basemap. @@ -45,6 +47,7 @@ Shows off the UI components included in the offline plugin. Show current location in the Fragment Show symbols on a map + Synchronise a view on a map None diff --git a/plugin-markerview/.gitignore b/plugin-markerview/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/plugin-markerview/.gitignore @@ -0,0 +1 @@ +/build diff --git a/plugin-markerview/build.gradle b/plugin-markerview/build.gradle new file mode 100644 index 000000000..aa1c865b3 --- /dev/null +++ b/plugin-markerview/build.gradle @@ -0,0 +1,47 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion androidVersions.compileSdkVersion + buildToolsVersion androidVersions.buildToolsVersion + + defaultConfig { + minSdkVersion androidVersions.minSdkVersion + targetSdkVersion androidVersions.targetSdkVersion + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + configurations { + javadocDeps + } + + lintOptions { + abortOnError false + } + + testOptions { + unitTests.returnDefaultValues true + unitTests.all { + jacoco { + includeNoLocationClasses true + } + } + } + + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } +} + +dependencies { + implementation dependenciesList.supportAppcompatV7 + implementation dependenciesList.mapboxMapSdk + javadocDeps dependenciesList.mapboxMapSdk + testImplementation dependenciesList.junit + testImplementation dependenciesList.mockito +} + +apply from: "${rootDir}/gradle/javadoc.gradle" +apply from: "${rootDir}/gradle/publish.gradle" +apply from: "${rootDir}/gradle/checkstyle.gradle" +apply from: "${rootDir}/gradle/jacoco.gradle" \ No newline at end of file diff --git a/plugin-markerview/gradle.properties b/plugin-markerview/gradle.properties new file mode 100644 index 000000000..79ffea1f8 --- /dev/null +++ b/plugin-markerview/gradle.properties @@ -0,0 +1,5 @@ +VERSION_NAME=0.1.0-SNAPSHOT +POM_ARTIFACT_ID=mapbox-android-plugin-markerview +POM_NAME=Mapbox Android MarkerView Plugin +POM_DESCRIPTION=Mapbox Android MarkerView Plugin +POM_PACKAGING=aar \ No newline at end of file diff --git a/plugin-markerview/proguard-rules.pro b/plugin-markerview/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/plugin-markerview/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/plugin-markerview/src/main/AndroidManifest.xml b/plugin-markerview/src/main/AndroidManifest.xml new file mode 100644 index 000000000..c53efedda --- /dev/null +++ b/plugin-markerview/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/plugin-markerview/src/main/java/com/mapbox/mapboxsdk/plugins/markerview/MarkerView.java b/plugin-markerview/src/main/java/com/mapbox/mapboxsdk/plugins/markerview/MarkerView.java new file mode 100644 index 000000000..bf6dbe955 --- /dev/null +++ b/plugin-markerview/src/main/java/com/mapbox/mapboxsdk/plugins/markerview/MarkerView.java @@ -0,0 +1,83 @@ +package com.mapbox.mapboxsdk.plugins.markerview; + +import android.graphics.PointF; +import android.support.annotation.NonNull; +import android.view.View; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.Projection; + +/** + * MarkerView class wraps a latitude-longitude pair with a Android SDK View. + *

+ * It can be used in conjuction with {@link MarkerViewManager} to synchronise the Android SDK View on top + * of map at the latitude-longitude pair. + *

+ */ +public class MarkerView { + + private final View view; + private LatLng latLng; + private Projection projection; + private OnPositionUpdateListener onPositionUpdateListener; + + /** + * Create a MarkerView + * + * @param latLng latitude-longitude pair + * @param view an Android SDK View + */ + public MarkerView(@NonNull LatLng latLng, @NonNull View view) { + this.latLng = latLng; + this.view = view; + } + + /** + * Update the location of the MarkerView on the map. + *

+ * Provided as a latitude-longitude pair. + *

+ * + * @param latLng latitude-longitude pair + */ + public void setLatLng(@NonNull LatLng latLng) { + this.latLng = latLng; + update(); + } + + /** + * Set a callback to be invoked when position placement is calculated. + *

+ * Can be used to offset a MarkerView on screen. + *

+ * + * @param onPositionUpdateListener callback to be invoked when position placement is calculated + */ + public void setOnPositionUpdateListener(OnPositionUpdateListener onPositionUpdateListener) { + this.onPositionUpdateListener = onPositionUpdateListener; + } + + /** + * Callback definition that is invoked when position placement of a MarkerView is calculated. + */ + public interface OnPositionUpdateListener { + PointF onUpdate(PointF pointF); + } + + void setProjection(Projection projection) { + this.projection = projection; + } + + View getView() { + return view; + } + + void update() { + PointF point = projection.toScreenLocation(latLng); + if (onPositionUpdateListener != null) { + point = onPositionUpdateListener.onUpdate(point); + } + view.setX(point.x); + view.setY(point.y); + } + +} \ No newline at end of file diff --git a/plugin-markerview/src/main/java/com/mapbox/mapboxsdk/plugins/markerview/MarkerViewManager.java b/plugin-markerview/src/main/java/com/mapbox/mapboxsdk/plugins/markerview/MarkerViewManager.java new file mode 100644 index 000000000..c69353959 --- /dev/null +++ b/plugin-markerview/src/main/java/com/mapbox/mapboxsdk/plugins/markerview/MarkerViewManager.java @@ -0,0 +1,92 @@ +package com.mapbox.mapboxsdk.plugins.markerview; + +import android.support.annotation.NonNull; +import android.support.annotation.UiThread; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class responsible for synchronising views at a LatLng on top of a Map. + */ +public class MarkerViewManager implements MapView.OnMapChangedListener { + + private final MapView mapView; + private final MapboxMap mapboxMap; + private final List markers = new ArrayList<>(); + private boolean initialised; + + /** + * Create a MarkerViewManager. + * + * @param mapView the MapView used to synchronise views on + * @param mapboxMap the MapboxMap to synchronise views with + */ + public MarkerViewManager(MapView mapView, MapboxMap mapboxMap) { + this.mapView = mapView; + this.mapboxMap = mapboxMap; + } + + /** + * Destroys the MarkerViewManager. + *

+ * Should be called before MapView#onDestroy + *

+ */ + @UiThread + public void onDestroy() { + markers.clear(); + mapView.removeOnMapChangedListener(this); + initialised = false; + } + + /** + * Add a MarkerView to the map using MarkerView and LatLng. + * + * @param markerView the markerView to synchronise on the map + */ + @UiThread + public void addMarker(@NonNull MarkerView markerView) { + if (mapView.isDestroyed() || markers.contains(markerView)) { + return; + } + + if (!initialised) { + initialised = true; + mapView.addOnMapChangedListener(this); + } + markerView.setProjection(mapboxMap.getProjection()); + mapView.addView(markerView.getView()); + markers.add(markerView); + } + + /** + * Remove an existing markerView from the map. + * + * @param markerView the markerView to be removed from the map + */ + @UiThread + public void removeMarker(@NonNull MarkerView markerView) { + if (mapView.isDestroyed() || !markers.contains(markerView)) { + return; + } + + mapView.removeView(markerView.getView()); + markers.remove(markerView); + } + + @Override + public void onMapChanged(int change) { + if (change == MapView.DID_FINISH_RENDERING_FRAME_FULLY_RENDERED) { + update(); + } + } + + private void update() { + for (MarkerView marker : markers) { + marker.update(); + } + } +} diff --git a/settings.gradle b/settings.gradle index edeee15c4..b0f485e60 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,3 +6,4 @@ include ':plugin-places' include ':plugin-offline' include ':plugin-localization' include ':plugin-annotation' +include ':plugin-markerview' \ No newline at end of file