Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Merge pull request #3127 from mapbox/3115-multiple-infowindows
Browse files Browse the repository at this point in the history
3115 multiple infowindows + leave open while panning
  • Loading branch information
zugaldia committed Nov 30, 2015
2 parents 68c0237 + e9d749b commit 48504ba
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
/**
* A tooltip view
*/
final class InfoWindow {
public class InfoWindow {

private WeakReference<Marker> mBoundMarker;
private WeakReference<MapView> mMapView;
private float mMarkerHeightOffset;
private float mViewWidthOffset;
private PointF mCoordinates;
private boolean mIsVisible;
protected View mView;

Expand Down Expand Up @@ -86,22 +89,26 @@ InfoWindow open(Marker boundMarker, LatLng position, int offsetX, int offsetY) {
MapView.LayoutParams lp = new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT, MapView.LayoutParams.WRAP_CONTENT);
mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

// Calculate default Android x,y coordinate
PointF coords = mMapView.get().toScreenLocation(position);
float x = coords.x - (mView.getMeasuredWidth() / 2) + offsetX;
float y = coords.y - mView.getMeasuredHeight() + offsetY;

// get right/left popup window
float rightSideInfowWindow = x + mView.getMeasuredWidth();
float leftSideInfoWindow = x;
// Calculate y-offset for update method
mMarkerHeightOffset = -mView.getMeasuredHeight() + offsetY;

// get right/left map view
final float mapRight = mMapView.get().getRight();
final float mapLeft = mMapView.get().getLeft();
// Calculate default Android x,y coordinate
mCoordinates = mMapView.get().toScreenLocation(position);
float x = mCoordinates.x - (mView.getMeasuredWidth() / 2) + offsetX;
float y = mCoordinates.y - mView.getMeasuredHeight() + offsetY;

if (mView instanceof InfoWindowView) {
// only apply repositioning/margin for InfoWindowView
Resources resources = mMapView.get().getContext().getResources();

// get right/left popup window
float rightSideInfowWindow = x + mView.getMeasuredWidth();
float leftSideInfoWindow = x;

// get right/left map view
final float mapRight = mMapView.get().getRight();
final float mapLeft = mMapView.get().getLeft();

float marginHorizontal = resources.getDimension(R.dimen.infowindow_margin);
float tipViewOffset = resources.getDimension(R.dimen.infowindow_tipview_width) / 2;
float tipViewMarginLeft = mView.getMeasuredWidth() / 2 - tipViewOffset;
Expand Down Expand Up @@ -129,15 +136,13 @@ InfoWindow open(Marker boundMarker, LatLng position, int offsetX, int offsetY) {
if (outOfBoundsRight && mapRight - rightSideInfowWindow < marginHorizontal) {
x -= marginHorizontal - (mapRight - rightSideInfowWindow);
tipViewMarginLeft += marginHorizontal - (mapRight - rightSideInfowWindow) - tipViewOffset;

leftSideInfoWindow = x;
}

// Add margin left
if (outOfBoundsLeft && leftSideInfoWindow - mapLeft < marginHorizontal) {
x += marginHorizontal - (leftSideInfoWindow - mapLeft);
tipViewMarginLeft -= (marginHorizontal - (leftSideInfoWindow - mapLeft)) - tipViewOffset;

}

// Adjust tipView
Expand All @@ -149,6 +154,9 @@ InfoWindow open(Marker boundMarker, LatLng position, int offsetX, int offsetY) {
mView.setX(x);
mView.setY(y);

// Calculate x-offset for update method
mViewWidthOffset = x - mCoordinates.x - offsetX;

close(); //if it was already opened
mMapView.get().addView(mView, lp);
mIsVisible = true;
Expand Down Expand Up @@ -196,7 +204,7 @@ void adaptDefaultMarker(Marker overlayItem) {
}

private void onClose() {
mMapView.get().deselectMarker();
mMapView.get().deselectMarker(getBoundMarker());
}

InfoWindow setBoundMarker(Marker boundMarker) {
Expand Down Expand Up @@ -226,4 +234,15 @@ private static void setResIds(Context context) {
.getIdentifier("id/infowindow_subdescription", null, packageName);
mImageId = context.getResources().getIdentifier("id/infowindow_image", null, packageName);
}

public void update() {
MapView mapView = mMapView.get();
Marker marker = mBoundMarker.get();
if (mapView != null && marker != null) {
mCoordinates = mapView.toScreenLocation(marker.getPosition());
mView.setX(mCoordinates.x + mViewWidthOffset);
mView.setY(mCoordinates.y + mMarkerHeightOffset);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ void setTitle(String title) {
/**
* Do not use this method. Used internally by the SDK.
*/
public void showInfoWindow() {
public InfoWindow showInfoWindow() {
if (getMapView() == null) {
return;
return null;
}

MapView.InfoWindowAdapter infoWindowAdapter = getMapView().getInfoWindowAdapter();
Expand All @@ -91,17 +91,18 @@ public void showInfoWindow() {
if (content != null) {
infoWindow = new InfoWindow(content, getMapView());
showInfoWindow(infoWindow);
return;
return infoWindow;
}
}

getInfoWindow().adaptDefaultMarker(this);
showInfoWindow(getInfoWindow());
return showInfoWindow(getInfoWindow());
}

private void showInfoWindow(InfoWindow iw) {
private InfoWindow showInfoWindow(InfoWindow iw) {
iw.open(this, getPosition(), 0, topOffsetPixels);
infoWindowShown = true;
return iw;
}

private InfoWindow getInfoWindow() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.Polygon;
Expand Down Expand Up @@ -202,7 +203,8 @@ public final class MapView extends FrameLayout {
// Every annotation that has been added to the map
private final List<Annotation> mAnnotations = new ArrayList<>();
private List<Marker> mMarkersNearLastTap = new ArrayList<>();
private Marker mSelectedMarker;
private List<Marker> mSelectedMarkers = new ArrayList<>();
private List<InfoWindow> mInfoWindows = new ArrayList<>();
private InfoWindowAdapter mInfoWindowAdapter;
private SpriteFactory mSpriteFactory;
private ArrayList<Sprite> mSprites = new ArrayList<>();
Expand Down Expand Up @@ -239,6 +241,7 @@ public final class MapView extends FrameLayout {
private boolean mZoomEnabled = true;
private boolean mScrollEnabled = true;
private boolean mRotateEnabled = true;
private boolean mAllowConcurrentMultipleOpenInfoWindows = false;
private String mStyleUrl;

//
Expand Down Expand Up @@ -849,10 +852,6 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
addOnMapChangedListener(new OnMapChangedListener() {
@Override
public void onMapChanged(@MapChange int change) {
if ((change == REGION_WILL_CHANGE) || (change == REGION_WILL_CHANGE_ANIMATED)) {
deselectMarker();
}

if (change == DID_FINISH_LOADING_MAP) {
reloadSprites();
reloadMarkers();
Expand Down Expand Up @@ -1336,6 +1335,30 @@ private void zoom(boolean zoomIn, float x, float y) {
}
}

//
// InfoWindows
//

/**
* Changes whether the map allows concurrent multiple infowindows to be shown.
*
* @param allow If true, map allows concurrent multiple infowindows to be shown.
*/
@UiThread
public void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) {
this.mAllowConcurrentMultipleOpenInfoWindows = allow;
}

/**
* Returns whether the map allows concurrent multiple infowindows to be shown.
*
* @return If true, map allows concurrent multiple infowindows to be shown.
*/
@UiThread
public boolean isAllowConcurrentMultipleOpenInfoWindows() {
return this.mAllowConcurrentMultipleOpenInfoWindows;
}

//
// Debug
//
Expand Down Expand Up @@ -2047,7 +2070,8 @@ public double getMetersPerPixelAtLatitude(@FloatRange(from = -180, to = 180) dou

/**
* Selects a marker. The selected marker will have it's info window opened.
* Any other open info windows will be closed.
* Any other open info windows will be closed unless isAllowConcurrentMultipleOpenInfoWindows()
* is true.
* <p/>
* Selecting an already selected marker will have no effect.
*
Expand All @@ -2060,12 +2084,14 @@ public void selectMarker(@NonNull Marker marker) {
return;
}

if (marker == mSelectedMarker) {
if (mSelectedMarkers.contains(marker)) {
return;
}

// Need to deselect any currently selected annotation first
deselectMarker();
if (!isAllowConcurrentMultipleOpenInfoWindows()) {
deselectMarkers();
}

boolean handledDefaultClick = false;
if (mOnMarkerClickListener != null) {
Expand All @@ -2074,26 +2100,46 @@ public void selectMarker(@NonNull Marker marker) {
}

if (!handledDefaultClick) {
// default behaviour
// Can't do this as InfoWindow will get hidden
//setCenterCoordinate(marker.getPosition(), true);
marker.showInfoWindow();
// default behaviour show InfoWindow
mInfoWindows.add(marker.showInfoWindow());
}

mSelectedMarker = marker;
mSelectedMarkers.add(marker);
}

/**
* Deselects any currently selected marker. The selected marker will have it's info window closed.
* Deselects any currently selected marker. All markers will have it's info window closed.
*/
@UiThread
public void deselectMarker() {
if (mSelectedMarker != null) {
if (mSelectedMarker.isInfoWindowShown()) {
mSelectedMarker.hideInfoWindow();
mSelectedMarker = null;
public void deselectMarkers() {
if (mSelectedMarkers.isEmpty()) {
return;
}

for (Marker marker : mSelectedMarkers) {
if (marker.isInfoWindowShown()) {
marker.hideInfoWindow();
}
}

// Removes all selected markers from the list
mSelectedMarkers.clear();
}

/**
* Deselects a currently selected marker. The selected marker will have it's info window closed.
*/
@UiThread
public void deselectMarker(@NonNull Marker marker) {
if (!mSelectedMarkers.contains(marker)) {
return;
}

if (marker.isInfoWindowShown()) {
marker.hideInfoWindow();
}

mSelectedMarkers.remove(marker);
}

//
Expand Down Expand Up @@ -2171,8 +2217,8 @@ private void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, dou
*/
@UiThread
@Nullable
public Marker getSelectedMarker() {
return mSelectedMarker;
public List<Marker> getSelectedMarkers() {
return mSelectedMarkers;
}

private void adjustTopOffsetPixels() {
Expand All @@ -2186,12 +2232,12 @@ private void adjustTopOffsetPixels() {
}
}

if (mSelectedMarker != null) {
if (mSelectedMarker.isInfoWindowShown()) {
Marker temp = mSelectedMarker;
for (Marker marker : mSelectedMarkers) {
if (marker.isInfoWindowShown()) {
Marker temp = marker;
temp.hideInfoWindow();
temp.showInfoWindow();
mSelectedMarker = temp;
marker = temp;
}
}
}
Expand Down Expand Up @@ -2272,6 +2318,9 @@ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int h
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
mCompassView.update(getDirection());
mUserLocationView.update();
for (InfoWindow infoWindow : mInfoWindows) {
infoWindow.update();
}
}
}

Expand Down Expand Up @@ -2482,19 +2531,24 @@ public boolean onSingleTapConfirmed(MotionEvent e) {
Collections.sort(nearbyMarkers);

if (nearbyMarkers == mMarkersNearLastTap) {

// TODO: We still need to adapt this logic to the new mSelectedMarkers list,
// though the basic functionality is there.

// the selection candidates haven't changed; cycle through them
if (mSelectedMarker != null && (mSelectedMarker.getId() == mMarkersNearLastTap.get(mMarkersNearLastTap.size() - 1).getId())) {
// the selected marker is the last in the set; cycle back to the first
// note: this could be the selected marker if only one in set
newSelectedMarkerId = mMarkersNearLastTap.get(0).getId();
} else if (mSelectedMarker != null) {
// otherwise increment the selection through the candidates
long result = mMarkersNearLastTap.indexOf(mSelectedMarker);
newSelectedMarkerId = mMarkersNearLastTap.get((int) result + 1).getId();
} else {
// if (mSelectedMarker != null
// && (mSelectedMarker.getId() == mMarkersNearLastTap.get(mMarkersNearLastTap.size() - 1).getId())) {
// // the selected marker is the last in the set; cycle back to the first
// // note: this could be the selected marker if only one in set
// newSelectedMarkerId = mMarkersNearLastTap.get(0).getId();
// } else if (mSelectedMarker != null) {
// // otherwise increment the selection through the candidates
// long result = mMarkersNearLastTap.indexOf(mSelectedMarker);
// newSelectedMarkerId = mMarkersNearLastTap.get((int) result + 1).getId();
// } else {
// no current selection; select the first one
newSelectedMarkerId = mMarkersNearLastTap.get(0).getId();
}
// }
} else {
// start tracking a new set of nearby markers
mMarkersNearLastTap = nearbyMarkers;
Expand All @@ -2515,7 +2569,7 @@ public boolean onSingleTapConfirmed(MotionEvent e) {
Annotation annotation = mAnnotations.get(i);
if (annotation instanceof Marker) {
if (annotation.getId() == newSelectedMarkerId) {
if (mSelectedMarker == null || annotation.getId() != mSelectedMarker.getId()) {
if (mSelectedMarkers.isEmpty() || !mSelectedMarkers.contains(annotation)) {
selectMarker((Marker) annotation);
}
break;
Expand All @@ -2525,7 +2579,7 @@ public boolean onSingleTapConfirmed(MotionEvent e) {

} else {
// deselect any selected marker
deselectMarker();
deselectMarkers();

// notify app of map click
if (mOnMapClickListener != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ protected void onCreate(Bundle savedInstanceState) {
mMapView.setAccessToken(ApiAccess.getToken(this));
mMapView.onCreate(savedInstanceState);

// Enable to let concurrent multiple infowindows to be shown.
//mMapView.setAllowConcurrentMultipleOpenInfoWindows(true);

mMapView.addMarker(new MarkerOptions()
.title("Intersection")
.snippet("H St NW with 15th St NW")
Expand Down
Loading

0 comments on commit 48504ba

Please sign in to comment.