[android] #5171 - introduce new select/deselect animation system for view markers
This commit is contained in:
committed by
Tobrun
parent
4094987fa0
commit
436c23c40b
@@ -30,6 +30,7 @@ public abstract class BaseMarkerViewOptions<U extends MarkerView, T extends Base
|
||||
protected int deselectAnimRes;
|
||||
protected int rotation;
|
||||
protected boolean visible = true;
|
||||
protected boolean selected;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.mapbox.mapboxsdk.annotations;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
|
||||
@@ -31,15 +33,14 @@ public class MarkerView extends Marker {
|
||||
private boolean flat;
|
||||
private boolean visible = true;
|
||||
|
||||
private int selectAnimRes;
|
||||
private int deselectAnimRes;
|
||||
|
||||
private float tiltValue;
|
||||
private float rotation;
|
||||
private float alpha = 1;
|
||||
|
||||
private Icon markerViewIcon;
|
||||
|
||||
private boolean selected;
|
||||
|
||||
/**
|
||||
* Publicly hidden default constructor
|
||||
*/
|
||||
@@ -58,12 +59,11 @@ public class MarkerView extends Marker {
|
||||
this.infoWindowAnchorU = baseMarkerViewOptions.getInfoWindowAnchorU();
|
||||
this.infoWindowAnchorV = baseMarkerViewOptions.getInfoWindowAnchorV();
|
||||
this.flat = baseMarkerViewOptions.isFlat();
|
||||
this.selectAnimRes = baseMarkerViewOptions.getSelectAnimRes();
|
||||
this.deselectAnimRes = baseMarkerViewOptions.getDeselectAnimRes();
|
||||
this.infoWindowAnchorU = baseMarkerViewOptions.infoWindowAnchorU;
|
||||
this.infoWindowAnchorV = baseMarkerViewOptions.infoWindowAnchorV;
|
||||
this.anchorU = baseMarkerViewOptions.anchorU;
|
||||
this.anchorV = baseMarkerViewOptions.anchorV;
|
||||
this.selected = baseMarkerViewOptions.selected;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,42 +195,6 @@ public class MarkerView extends Marker {
|
||||
this.flat = flat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the animator resource used to animate to the selected state of a MarkerView.
|
||||
*
|
||||
* @return the animator resource used
|
||||
*/
|
||||
public int getSelectAnimRes() {
|
||||
return selectAnimRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the animator resource used to animate to the deselected state of a MarkerView.
|
||||
*
|
||||
* @param selectAnimRes the animator resource used
|
||||
*/
|
||||
public void setSelectAnimRes(int selectAnimRes) {
|
||||
this.selectAnimRes = selectAnimRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the animator resource used to animate to the deslected state of a MarkerView.
|
||||
*
|
||||
* @return the animator resource used
|
||||
*/
|
||||
public int getDeselectAnimRes() {
|
||||
return deselectAnimRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the animator resource used to animate to the selected state of a MarkerView.
|
||||
*
|
||||
* @param deselectAnimRes the animator resource used
|
||||
*/
|
||||
public void setDeselectAnimRes(int deselectAnimRes) {
|
||||
this.deselectAnimRes = deselectAnimRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to get the current tilted value of a MarkerView.
|
||||
*
|
||||
@@ -338,6 +302,17 @@ public class MarkerView extends Marker {
|
||||
super.setIcon(transparentIcon);
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* For internal use only, use {@link MapboxMap#selectMarker(Marker)} instead.
|
||||
*/
|
||||
void setSelected(boolean selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the icon of the MarkerView.
|
||||
*
|
||||
|
||||
@@ -51,7 +51,6 @@ public class MarkerViewManager {
|
||||
this.mapView = mapView;
|
||||
this.markerViewMap = new HashMap<>();
|
||||
this.defaultMarkerViewAdapter = new ImageMarkerViewAdapter(mapView.getContext());
|
||||
// FIXME only add this if a MarkerView instance is added to MapboxMap
|
||||
this.markerViewAdapters.add(defaultMarkerViewAdapter);
|
||||
}
|
||||
|
||||
@@ -166,8 +165,7 @@ public class MarkerViewManager {
|
||||
/**
|
||||
* Animate a MarkerView to a deselected state.
|
||||
* <p>
|
||||
* The {@link MarkerView#getDeselectAnimRes()} will be called to get the related animation.
|
||||
* If non are provided, no animation will be started.
|
||||
* The {@link ImageMarkerViewAdapter#onDeselect(MarkerView, View)} will be called to execute an animation.
|
||||
* </p>
|
||||
*
|
||||
* @param marker the MarkerView to deselect
|
||||
@@ -175,13 +173,32 @@ public class MarkerViewManager {
|
||||
public void deselect(@NonNull MarkerView marker) {
|
||||
final View convertView = markerViewMap.get(marker);
|
||||
if (convertView != null) {
|
||||
int deselectAnimatorRes = marker.getDeselectAnimRes();
|
||||
if (deselectAnimatorRes != 0) {
|
||||
AnimatorUtils.animate(convertView, deselectAnimatorRes);
|
||||
for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
|
||||
if (adapter.getMarkerClass().equals(marker.getClass())) {
|
||||
adapter.onDeselect(marker, convertView);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void select(@NonNull MarkerView marker) {
|
||||
final View convertView = markerViewMap.get(marker);
|
||||
for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
|
||||
if (adapter.getMarkerClass().equals(marker.getClass())) {
|
||||
select(marker, convertView, adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter) {
|
||||
if (convertView != null) {
|
||||
if (adapter.onSelect(marker, convertView, false)) {
|
||||
mapboxMap.selectMarker(marker);
|
||||
}
|
||||
marker.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a MarkerView from a map.
|
||||
* <p>
|
||||
@@ -191,42 +208,35 @@ public class MarkerViewManager {
|
||||
* the {@link MarkerView} from the underlying collection if needed.
|
||||
* </p>
|
||||
*
|
||||
* @param marker the MarkerView to remove
|
||||
* @param removeFromMap flag indicating if a MarkerView will be removed from the collection.
|
||||
* @param marker the MarkerView to remove
|
||||
*/
|
||||
public void removeMarkerView(MarkerView marker, boolean removeFromMap) {
|
||||
public void removeMarkerView(MarkerView marker) {
|
||||
final View viewHolder = markerViewMap.get(marker);
|
||||
if (viewHolder != null && marker != null) {
|
||||
for (final MapboxMap.MarkerViewAdapter<?> adapter : markerViewAdapters) {
|
||||
if (adapter.getMarkerClass() == marker.getClass()) {
|
||||
|
||||
// get pool of Views associated to an adapter
|
||||
final Pools.SimplePool<View> viewPool = adapter.getViewReusePool();
|
||||
|
||||
// cancel ongoing animations
|
||||
viewHolder.animate().cancel();
|
||||
viewHolder.setAlpha(1);
|
||||
AnimatorUtils.alpha(viewHolder, 0, new AnimatorUtils.OnAnimationEndListener() {
|
||||
@Override
|
||||
public void onAnimationEnd() {
|
||||
viewHolder.setVisibility(View.GONE);
|
||||
viewPool.release(viewHolder);
|
||||
}
|
||||
});
|
||||
if (adapter.getMarkerClass().equals(marker.getClass())) {
|
||||
if (adapter.prepareViewForReuse(marker, viewHolder)) {
|
||||
adapter.releaseView(viewHolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (removeFromMap) {
|
||||
markerViewMap.remove(marker);
|
||||
}
|
||||
markerViewMap.remove(marker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a MarkerViewAdapter.
|
||||
* Add a MarkerViewAdapter to the MarkerViewManager.
|
||||
* <p>
|
||||
* The provided MarkerViewAdapter must use supply a generic subclass of MarkerView.
|
||||
* </p>
|
||||
*
|
||||
* @param markerViewAdapter the MarkerViewAdapter to add
|
||||
*/
|
||||
public void addMarkerViewAdapter(@Nullable MapboxMap.MarkerViewAdapter markerViewAdapter) {
|
||||
public void addMarkerViewAdapter(MapboxMap.MarkerViewAdapter markerViewAdapter) {
|
||||
if (markerViewAdapter.getMarkerClass().equals(MarkerView.class)) {
|
||||
throw new RuntimeException("Providing a custom MarkerViewAdapter requires subclassing MarkerView");
|
||||
}
|
||||
|
||||
if (!markerViewAdapters.contains(markerViewAdapter)) {
|
||||
markerViewAdapters.add(markerViewAdapter);
|
||||
invalidateViewMarkersInBounds();
|
||||
@@ -288,12 +298,13 @@ public class MarkerViewManager {
|
||||
if (!markers.contains(m)) {
|
||||
// remove marker
|
||||
convertView = markerViewMap.get(m);
|
||||
int deselectAnimRes = m.getDeselectAnimRes();
|
||||
if (deselectAnimRes != 0) {
|
||||
AnimatorUtils.animate(convertView, deselectAnimRes, 0);
|
||||
for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
|
||||
if (adapter.getMarkerClass().equals(m.getClass())) {
|
||||
adapter.prepareViewForReuse(m, convertView);
|
||||
adapter.releaseView(convertView);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
removeMarkerView(m, false);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,7 +312,7 @@ public class MarkerViewManager {
|
||||
for (final MarkerView marker : markers) {
|
||||
if (!markerViewMap.containsKey(marker)) {
|
||||
for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
|
||||
if (adapter.getMarkerClass() == marker.getClass()) {
|
||||
if (adapter.getMarkerClass().equals(marker.getClass())) {
|
||||
convertView = (View) adapter.getViewReusePool().acquire();
|
||||
final View adaptedView = adapter.getView(marker, convertView, mapView);
|
||||
if (adaptedView != null) {
|
||||
@@ -321,13 +332,11 @@ public class MarkerViewManager {
|
||||
if (mapboxMap.getSelectedMarkers().contains(marker)) {
|
||||
// if a marker to be shown was selected
|
||||
// replay that animation with duration 0
|
||||
int selectAnimRes = marker.getSelectAnimRes();
|
||||
if (selectAnimRes != 0) {
|
||||
AnimatorUtils.animate(convertView, selectAnimRes, 0);
|
||||
if (adapter.onSelect(marker, adaptedView, true)) {
|
||||
mapboxMap.selectMarker(marker);
|
||||
}
|
||||
}
|
||||
|
||||
final int animSelectRes = marker.getSelectAnimRes();
|
||||
adaptedView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
@@ -342,17 +351,7 @@ public class MarkerViewManager {
|
||||
int infoWindowOffsetY = (int) ((adaptedView.getHeight() * marker.getInfoWindowAnchorV()) - marker.getOffsetY());
|
||||
marker.setTopOffsetPixels(infoWindowOffsetY);
|
||||
marker.setRightOffsetPixels(infoWindowOffsetX);
|
||||
|
||||
if (animSelectRes != 0) {
|
||||
AnimatorUtils.animate(v, animSelectRes, new AnimatorUtils.OnAnimationEndListener() {
|
||||
@Override
|
||||
public void onAnimationEnd() {
|
||||
mapboxMap.selectMarker(marker);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mapboxMap.selectMarker(marker);
|
||||
}
|
||||
select(marker, v, adapter);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -82,8 +82,6 @@ public class MarkerViewOptions extends BaseMarkerViewOptions<MarkerView, MarkerV
|
||||
marker.setFlat(flat);
|
||||
marker.setAnchor(anchorU, anchorV);
|
||||
marker.setInfoWindowAnchor(infoWindowAnchorU, infoWindowAnchorV);
|
||||
marker.setSelectAnimRes(selectAnimRes);
|
||||
marker.setDeselectAnimRes(deselectAnimRes);
|
||||
marker.setRotation(rotation);
|
||||
marker.setVisible(visible);
|
||||
return marker;
|
||||
|
||||
@@ -951,7 +951,7 @@ public class MapboxMap {
|
||||
Marker marker = (Marker) annotation;
|
||||
marker.hideInfoWindow();
|
||||
if (marker instanceof MarkerView) {
|
||||
mMarkerViewManager.removeMarkerView((MarkerView) marker, true);
|
||||
mMarkerViewManager.removeMarkerView((MarkerView) marker);
|
||||
}
|
||||
}
|
||||
long id = annotation.getId();
|
||||
@@ -985,7 +985,7 @@ public class MapboxMap {
|
||||
Marker marker = (Marker) annotation;
|
||||
marker.hideInfoWindow();
|
||||
if (marker instanceof MarkerView) {
|
||||
mMarkerViewManager.removeMarkerView((MarkerView) marker, true);
|
||||
mMarkerViewManager.removeMarkerView((MarkerView) marker);
|
||||
}
|
||||
}
|
||||
ids[i] = annotationList.get(i).getId();
|
||||
@@ -1011,7 +1011,7 @@ public class MapboxMap {
|
||||
Marker marker = (Marker) annotation;
|
||||
marker.hideInfoWindow();
|
||||
if (marker instanceof MarkerView) {
|
||||
mMarkerViewManager.removeMarkerView((MarkerView) marker, true);
|
||||
mMarkerViewManager.removeMarkerView((MarkerView) marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1840,12 +1840,57 @@ public class MapboxMap {
|
||||
@Nullable
|
||||
public abstract View getView(@NonNull U marker, @NonNull View convertView, @NonNull ViewGroup parent);
|
||||
|
||||
/**
|
||||
* Called when an MarkerView is removed from the MapView or the View object is going to be reused.
|
||||
* <p>
|
||||
* <p>
|
||||
* This method should be used to reset an animated view back to it's original state for view reuse.
|
||||
* </p>
|
||||
* <p>
|
||||
* Returning true indicates you want to the view reuse to be handled automatically.
|
||||
* Returning false indicates you want to perform an animation and you are required calling {@link #releaseView(View)} yourself.
|
||||
* </p>
|
||||
*
|
||||
* @param marker the model representing the MarkerView
|
||||
* @param convertView the reusable view
|
||||
* @return true if you want reuse to occur automatically, false if you want to manage this yourself.
|
||||
*/
|
||||
public boolean prepareViewForReuse(@NonNull MarkerView marker, @NonNull View convertView) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a MarkerView is selected from the MapView.
|
||||
* <p>
|
||||
* Returning true from this method indicates you want to move the MarkerView to the selected state.
|
||||
* Returning false indicates you want to animate the View first an manually select the MarkerView when appropriate.
|
||||
* </p>
|
||||
*
|
||||
* @param marker the model representing the MarkerView
|
||||
* @param convertView the reusable view
|
||||
* @param reselectionFromRecycling indicates if the onSelect callback is the initial selection
|
||||
* callback or that selection occurs due to recreation of selected marker
|
||||
* @return true if you want to select the Marker immediately, false if you want to manage this yourself.
|
||||
*/
|
||||
public boolean onSelect(@NonNull U marker, @NonNull View convertView, boolean reselectionFromRecycling) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a MarkerView is deselected from the MapView.
|
||||
*
|
||||
* @param marker the model representing the MarkerView
|
||||
* @param convertView the reusable view
|
||||
*/
|
||||
public void onDeselect(@NonNull U marker, @NonNull View convertView) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the generic type of the used MarkerView.
|
||||
*
|
||||
* @return the generic type
|
||||
*/
|
||||
public Class<U> getMarkerClass() {
|
||||
public final Class<U> getMarkerClass() {
|
||||
return persistentClass;
|
||||
}
|
||||
|
||||
@@ -1854,7 +1899,7 @@ public class MapboxMap {
|
||||
*
|
||||
* @return the pool associated to this adapter
|
||||
*/
|
||||
public Pools.SimplePool<View> getViewReusePool() {
|
||||
public final Pools.SimplePool<View> getViewReusePool() {
|
||||
return mViewReusePool;
|
||||
}
|
||||
|
||||
@@ -1863,9 +1908,19 @@ public class MapboxMap {
|
||||
*
|
||||
* @return the context used
|
||||
*/
|
||||
public Context getContext() {
|
||||
public final Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a View to the ViewPool.
|
||||
*
|
||||
* @param view the view to be released
|
||||
*/
|
||||
public final void releaseView(View view) {
|
||||
view.setVisibility(View.GONE);
|
||||
mViewReusePool.release(view);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,28 +3,28 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.res.ResourcesCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.Icon;
|
||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerView;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
@@ -86,36 +86,6 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
|
||||
}
|
||||
}
|
||||
|
||||
public static class TextAdapter extends MapboxMap.MarkerViewAdapter<MarkerView> {
|
||||
|
||||
private LayoutInflater inflater;
|
||||
|
||||
public TextAdapter(@NonNull Context context) {
|
||||
super(context);
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View getView(@NonNull MarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
ViewHolder viewHolder;
|
||||
if (convertView == null) {
|
||||
viewHolder = new ViewHolder();
|
||||
convertView = inflater.inflate(R.layout.view_text_marker, parent, false);
|
||||
viewHolder.title = (TextView) convertView.findViewById(R.id.textView);
|
||||
convertView.setTag(viewHolder);
|
||||
} else {
|
||||
viewHolder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
viewHolder.title.setText(marker.getTitle());
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
TextView title;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
int amount = Integer.valueOf(getResources().getStringArray(R.array.bulk_marker_list)[position]);
|
||||
@@ -126,7 +96,6 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onLatLngListLoaded(List<LatLng> latLngs, int amount) {
|
||||
mLocations = latLngs;
|
||||
showMarkers(amount);
|
||||
@@ -140,26 +109,32 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
|
||||
}
|
||||
|
||||
if (mCustomMarkerView) {
|
||||
showNativeMarkers(amount);
|
||||
showViewMarkers(amount);
|
||||
} else {
|
||||
showGlMarkers(amount);
|
||||
}
|
||||
}
|
||||
|
||||
private void showNativeMarkers(int amount) {
|
||||
private void showViewMarkers(int amount) {
|
||||
DecimalFormat formatter = new DecimalFormat("#.#####");
|
||||
Random random = new Random();
|
||||
int randomIndex;
|
||||
|
||||
Drawable drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_droppin_24dp, getTheme());
|
||||
int redColor = ResourcesCompat.getColor(getResources(), android.R.color.holo_red_dark, getTheme());
|
||||
drawable.setColorFilter(redColor, PorterDuff.Mode.SRC_IN);
|
||||
Icon icon = IconFactory.getInstance(this).fromDrawable(drawable);
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
randomIndex = random.nextInt(mLocations.size());
|
||||
LatLng latLng = mLocations.get(randomIndex);
|
||||
mMapboxMap.addMarker(new MarkerViewOptions()
|
||||
.position(latLng)
|
||||
.icon(icon)
|
||||
.title(String.valueOf(i))
|
||||
.snippet(formatter.format(latLng.getLatitude()) + ", " + formatter.format(latLng.getLongitude())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showGlMarkers(int amount) {
|
||||
List<MarkerOptions> markerOptionsList = new ArrayList<>();
|
||||
@@ -247,9 +222,6 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
|
||||
showMarkers(amount);
|
||||
}
|
||||
|
||||
// add adapter
|
||||
mMapboxMap.getMarkerViewManager().addMarkerViewAdapter(new TextAdapter(BulkMarkerActivity.this));
|
||||
|
||||
mMapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
|
||||
@Override
|
||||
public void onMapChanged(@MapView.MapChange int change) {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package com.mapbox.mapboxsdk.testapp.activity.annotation;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorInflater;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
@@ -18,6 +22,8 @@ import android.widget.Toast;
|
||||
import com.mapbox.mapboxsdk.annotations.Icon;
|
||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerView;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
@@ -28,6 +34,8 @@ import com.mapbox.mapboxsdk.testapp.R;
|
||||
import com.mapbox.mapboxsdk.testapp.model.annotations.CountryMarkerOptions;
|
||||
import com.mapbox.mapboxsdk.testapp.model.annotations.CountryMarkerView;
|
||||
import com.mapbox.mapboxsdk.testapp.model.annotations.CountryMarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.testapp.model.annotations.TextMarkerView;
|
||||
import com.mapbox.mapboxsdk.testapp.model.annotations.TextMarkerViewOptions;
|
||||
|
||||
public class MarkerViewActivity extends AppCompatActivity {
|
||||
|
||||
@@ -35,13 +43,10 @@ public class MarkerViewActivity extends AppCompatActivity {
|
||||
private MapView mMapView;
|
||||
|
||||
private final static LatLng[] LAT_LNGS = new LatLng[]{
|
||||
new LatLng(38.907327, -77.041293),
|
||||
new LatLng(38.897424, -77.036508),
|
||||
new LatLng(38.909698, -77.029642),
|
||||
new LatLng(38.907227, -77.036530),
|
||||
new LatLng(38.905607, -77.031916),
|
||||
new LatLng(38.897424, -77.036508),
|
||||
new LatLng(38.897642, -77.041980),
|
||||
new LatLng(38.889876, -77.008849),
|
||||
new LatLng(38.889441, -77.050134)
|
||||
};
|
||||
|
||||
@@ -83,24 +88,40 @@ public class MarkerViewActivity extends AppCompatActivity {
|
||||
);
|
||||
}
|
||||
|
||||
// add child classes of ViewMarker
|
||||
// add custom ViewMarker
|
||||
CountryMarkerViewOptions options = new CountryMarkerViewOptions();
|
||||
options.flagRes(R.drawable.icon_burned);
|
||||
options.abbrevName("Mapbox");
|
||||
options.title("Hello");
|
||||
options.position(new LatLng(38.899774, -77.023237));
|
||||
options.selectAnimatorResource(R.animator.rotate_360);
|
||||
options.deselectAnimatorResource(R.animator.rotate_360);
|
||||
options.flat(true);
|
||||
mapboxMap.addMarker(options);
|
||||
|
||||
// add default GL marker
|
||||
mMapboxMap.addMarker(new CountryMarkerOptions()
|
||||
mMapboxMap.addMarker(new MarkerOptions()
|
||||
.title("United States")
|
||||
.position(new LatLng(38.902580, -77.050102))
|
||||
);
|
||||
|
||||
mMapboxMap.addMarker(new TextMarkerViewOptions()
|
||||
.text("A")
|
||||
.position(new LatLng(38.889876, -77.008849))
|
||||
);
|
||||
|
||||
mMapboxMap.addMarker(new TextMarkerViewOptions()
|
||||
.text("B")
|
||||
.position(new LatLng(38.907327, -77.041293))
|
||||
);
|
||||
|
||||
mMapboxMap.addMarker(new TextMarkerViewOptions()
|
||||
.text("C")
|
||||
.position(new LatLng(38.897642, -77.041980))
|
||||
);
|
||||
|
||||
// set adapters for child classes of ViewMarker
|
||||
markerViewManager.addMarkerViewAdapter(new CountryAdapter(MarkerViewActivity.this));
|
||||
markerViewManager.addMarkerViewAdapter(new CountryAdapter(MarkerViewActivity.this, mapboxMap));
|
||||
markerViewManager.addMarkerViewAdapter(new TextAdapter(MarkerViewActivity.this, mapboxMap));
|
||||
|
||||
// add a change listener to validate the size of amount of child views
|
||||
mMapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
|
||||
@@ -129,10 +150,12 @@ public class MarkerViewActivity extends AppCompatActivity {
|
||||
private static class CountryAdapter extends MapboxMap.MarkerViewAdapter<CountryMarkerView> {
|
||||
|
||||
private LayoutInflater inflater;
|
||||
private MapboxMap mapboxMap;
|
||||
|
||||
public CountryAdapter(@NonNull Context context) {
|
||||
public CountryAdapter(@NonNull Context context, @NonNull MapboxMap mapboxMap) {
|
||||
super(context);
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
this.mapboxMap = mapboxMap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -153,12 +176,143 @@ public class MarkerViewActivity extends AppCompatActivity {
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSelect(@NonNull final CountryMarkerView marker, @NonNull final View convertView, boolean reselectionForViewReuse) {
|
||||
convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(convertView, View.ROTATION, 0, 360);
|
||||
rotateAnimator.setDuration(reselectionForViewReuse ? 0 : 350);
|
||||
rotateAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
convertView.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
mapboxMap.selectMarker(marker);
|
||||
}
|
||||
});
|
||||
rotateAnimator.start();
|
||||
|
||||
// false indicates that we are calling selectMarker after our animation ourselves
|
||||
// true will let the system call it for you, which will result in showing an InfoWindow instantly
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeselect(@NonNull CountryMarkerView marker, @NonNull final View convertView) {
|
||||
convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(convertView, View.ROTATION, 360, 0);
|
||||
rotateAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
convertView.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
}
|
||||
});
|
||||
rotateAnimator.start();
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
ImageView flag;
|
||||
TextView abbrev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class TextAdapter extends MapboxMap.MarkerViewAdapter<TextMarkerView> {
|
||||
|
||||
private LayoutInflater inflater;
|
||||
private MapboxMap mapboxMap;
|
||||
|
||||
public TextAdapter(@NonNull Context context, @NonNull MapboxMap mapboxMap) {
|
||||
super(context);
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
this.mapboxMap = mapboxMap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View getView(@NonNull TextMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
ViewHolder viewHolder;
|
||||
if (convertView == null) {
|
||||
viewHolder = new ViewHolder();
|
||||
convertView = inflater.inflate(R.layout.view_text_marker, parent, false);
|
||||
viewHolder.textView = (TextView) convertView.findViewById(R.id.textView);
|
||||
convertView.setTag(viewHolder);
|
||||
} else {
|
||||
viewHolder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
viewHolder.textView.setText(marker.getText());
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSelect(@NonNull final TextMarkerView marker, @NonNull final View convertView, boolean reselectionForViewReuse) {
|
||||
animateGrow(marker, convertView, 0);
|
||||
|
||||
// false indicates that we are calling selectMarker after our animation ourselves
|
||||
// true will let the system call it for you, which will result in showing an InfoWindow instantly
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeselect(@NonNull TextMarkerView marker, @NonNull final View convertView) {
|
||||
animateShrink(convertView, 350);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepareViewForReuse(@NonNull MarkerView marker, @NonNull View convertView) {
|
||||
// this method is called before a view will be reused, we need to restore view state
|
||||
// as we have scaled the view in onSelect. If not correctly applied other MarkerView will
|
||||
// become large since these have been recycled
|
||||
|
||||
// cancel ongoing animation
|
||||
convertView.animate().cancel();
|
||||
|
||||
if (marker.isSelected()) {
|
||||
// shrink view to be able to be reused
|
||||
animateShrink(convertView, 0);
|
||||
}
|
||||
|
||||
// true if you want reuse to occur automatically, false if you want to manage this yourself
|
||||
return true;
|
||||
}
|
||||
|
||||
private void animateGrow(@NonNull final MarkerView marker, @NonNull final View convertView, int duration) {
|
||||
convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
Animator animator = AnimatorInflater.loadAnimator(convertView.getContext(), R.animator.scale_up);
|
||||
animator.setDuration(duration);
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
convertView.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
mapboxMap.selectMarker(marker);
|
||||
}
|
||||
});
|
||||
animator.setTarget(convertView);
|
||||
animator.start();
|
||||
}
|
||||
|
||||
private void animateShrink(@NonNull final View convertView, int duration) {
|
||||
convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
Animator animator = AnimatorInflater.loadAnimator(convertView.getContext(), R.animator.scale_down);
|
||||
animator.setDuration(duration);
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
convertView.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
}
|
||||
});
|
||||
animator.setTarget(convertView);
|
||||
animator.start();
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
TextView textView;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
@@ -64,6 +64,7 @@ public class CountryMarkerViewOptions extends BaseMarkerViewOptions<CountryMarke
|
||||
out.writeInt(getSelectAnimRes());
|
||||
out.writeInt(getDeselectAnimRes());
|
||||
out.writeInt(getRotation());
|
||||
out.writeByte((byte) (selected ? 1 :0));
|
||||
Icon icon = getIcon();
|
||||
out.writeByte((byte) (icon != null ? 1 : 0));
|
||||
if (icon != null) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.mapbox.mapboxsdk.testapp.model.annotations;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerView;
|
||||
|
||||
public class TextMarkerView extends MarkerView {
|
||||
|
||||
private String text;
|
||||
|
||||
public TextMarkerView(BaseMarkerViewOptions baseMarkerViewOptions, String text) {
|
||||
super(baseMarkerViewOptions);
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.mapbox.mapboxsdk.testapp.model.annotations;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.Icon;
|
||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
|
||||
public class TextMarkerViewOptions extends BaseMarkerViewOptions<TextMarkerView,TextMarkerViewOptions> {
|
||||
|
||||
private String text;
|
||||
|
||||
public TextMarkerViewOptions() {
|
||||
}
|
||||
|
||||
protected TextMarkerViewOptions(Parcel in) {
|
||||
position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
|
||||
snippet(in.readString());
|
||||
title(in.readString());
|
||||
flat(in.readByte() != 0);
|
||||
anchor(in.readFloat(), in.readFloat());
|
||||
infoWindowAnchor(in.readFloat(), in.readFloat());
|
||||
selectAnimatorResource(in.readInt());
|
||||
deselectAnimatorResource(in.readInt());
|
||||
rotation(in.readInt());
|
||||
if (in.readByte() != 0) {
|
||||
// this means we have an icon
|
||||
String iconId = in.readString();
|
||||
Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
|
||||
Icon icon = IconFactory.recreate(iconId, iconBitmap);
|
||||
icon(icon);
|
||||
}
|
||||
text(in.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextMarkerViewOptions getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeParcelable(getPosition(), flags);
|
||||
out.writeString(getSnippet());
|
||||
out.writeString(getTitle());
|
||||
out.writeByte((byte) (isFlat() ? 1 : 0));
|
||||
out.writeFloat(getAnchorU());
|
||||
out.writeFloat(getAnchorV());
|
||||
out.writeFloat(getInfoWindowAnchorU());
|
||||
out.writeFloat(getInfoWindowAnchorV());
|
||||
out.writeInt(getSelectAnimRes());
|
||||
out.writeInt(getDeselectAnimRes());
|
||||
out.writeInt(getRotation());
|
||||
Icon icon = getIcon();
|
||||
out.writeByte((byte) (icon != null ? 1 : 0));
|
||||
if (icon != null) {
|
||||
out.writeString(getIcon().getId());
|
||||
out.writeParcelable(getIcon().getBitmap(), flags);
|
||||
}
|
||||
out.writeString(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextMarkerView getMarker() {
|
||||
return new TextMarkerView(this, text);
|
||||
}
|
||||
|
||||
public TextMarkerViewOptions text(String text) {
|
||||
this.text = text;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<CountryMarkerViewOptions> CREATOR
|
||||
= new Parcelable.Creator<CountryMarkerViewOptions>() {
|
||||
public CountryMarkerViewOptions createFromParcel(Parcel in) {
|
||||
return new CountryMarkerViewOptions(in);
|
||||
}
|
||||
|
||||
public CountryMarkerViewOptions[] newArray(int size) {
|
||||
return new CountryMarkerViewOptions[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package com.mapbox.mapboxsdk.annotations;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.testapp.R;
|
||||
import com.mapbox.mapboxsdk.utils.MockParcel;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -97,22 +96,6 @@ public class MarkerViewTest {
|
||||
assertEquals("anchorU should match ", 0, marker.getInfoWindowAnchorV(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectAnimRes() {
|
||||
int animatorRes = R.animator.rotate_360;
|
||||
MarkerViewOptions markerOptions = new MarkerViewOptions().selectAnimatorResource(animatorRes);
|
||||
MarkerView marker = markerOptions.getMarker();
|
||||
assertEquals("select animator resource should match ", animatorRes, marker.getSelectAnimRes(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeselectAnimRes() {
|
||||
int animatorRes = R.animator.rotate_360;
|
||||
MarkerViewOptions markerOptions = new MarkerViewOptions().deselectAnimatorResource(animatorRes);
|
||||
MarkerView marker = markerOptions.getMarker();
|
||||
assertEquals("deselect animator resource should match ", animatorRes, marker.getDeselectAnimRes(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRotation() {
|
||||
int rotation = 90;
|
||||
|
||||
Reference in New Issue
Block a user