将 InfoWindow 添加到 FastPointOverlay - OsmDroid
Add InfoWindow to a FastPointOverlay - OsmDroid
最初我使用标记 class 实现了所需的功能,但是当点越来越多时性能会严重下降,所以我将 SimpleFastPointOverlay 与 PopUpwindow 结合使用。
public class OpenMapFragment extends Fragment {
private Map<Integer, MyPoint> myPointsMap;
private Context context;
private PageViewModel pageViewModel;
private MapView map = null;
private SimpleFastPointOverlay sfpo;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getParentFragment() != null) {
pageViewModel = new ViewModelProvider(getParentFragment()).get(PageViewModel.class);
}
context = requireActivity().getApplicationContext();
}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_open_map, container, false);
LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
map = root.findViewById(R.id.mapview);
map.setTileSource(TileSourceFactory.MAPNIK);
map.setMultiTouchControls(true);
myPointsMap = new HashMap<>();
pageViewModel.getMyPoints().observe(getViewLifecycleOwner(), myPointsList -> {
myPointsMap =
myPointsList.stream().collect(Collectors.toMap(MyPoint::getId, p -> p));
if (sfpo != null) {
map.getOverlays().remove(sfpo);
}
sfpo = simpleFastPointOverlayBuilder(myPointsList);
sfpo.setOnClickListener((points, point) -> {
MyPoint mp = myPointsMap
.get(Integer.valueOf(((LabelledGeoPoint) points.get(point)).getLabel()));
View popupView = inflater.inflate(R.layout.popup_window, null);
TextView txtId = popupView.findViewById(R.id.txt_id);
txtId.setText("id:" + mp.getId());
int width = LinearLayout.LayoutParams.WRAP_CONTENT;
int height = LinearLayout.LayoutParams.WRAP_CONTENT;
final PopupWindow popupWindow = new PopupWindow(popupView, width, height, true);
popupWindow.showAtLocation(getView(), Gravity.CENTER, 0, 0);
popupView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
popupWindow.dismiss();
return true;
}
});
});
map.getOverlays().add(sfpo);
});
return root;
}
private SimpleFastPointOverlay simpleFastPointOverlayBuilder(List<MyPoint> myPointList) {
List<IGeoPoint> points = new ArrayList<>();
Paint textStyle = new Paint();
textStyle.setStyle(Paint.Style.FILL);
textStyle.setColor(Color.parseColor("#111111"));
textStyle.setTextAlign(Paint.Align.CENTER);
textStyle.setTextSize(24);
Paint pointStyle = new Paint();
pointStyle.setStyle(Paint.Style.FILL);
pointStyle.setColor(Color.rgb(255, 0, 0));
for(MyPoint myPoint: myPointList) {
points.add(new StyledLabelledGeoPoint(myPoint.getLocationInfo().latitude,
myPoint.getLocationInfo().longitude, Integer.toString(myPoint.getId()),
pointStyle, textStyle));
}
SimplePointTheme pointTheme = new SimplePointTheme(points);
SimpleFastPointOverlayOptions opt = SimpleFastPointOverlayOptions.getDefaultStyle()
.setSymbol(SimpleFastPointOverlayOptions.Shape.CIRCLE)
.setAlgorithm(SimpleFastPointOverlayOptions.RenderingAlgorithm.MAXIMUM_OPTIMIZATION)
.setRadius(7).setIsClickable(true).setCellSize(12)
.setMinZoomShowLabels(12);
return new SimpleFastPointOverlay(pointTheme, opt);
}
@Override
public void onResume() {
super.onResume();
map.onResume();
}
@Override
public void onPause() {
super.onPause();
map.onPause();
}
}
虽然这是一种解决方法,但我不喜欢它,因为 popupView 位于显示的中心,并且无法与单击元素的位置相关联。有没有一种方法可以让我对 OsmDroid 的标记和信息窗口有类似的行为?
我终于找到了解决办法:
为了获得所需的功能,我应该在每次单击 simpleFastPoint 时添加一个标记,如果单击另一个标记,则删除前一个标记并添加一个新标记。所以性能仍然很好,但具有标记行为。我还让标记不可见
public class OpenMapFragment extends Fragment {
private Map<Integer, MyPoint> myPointsMap;
private Context context;
private PageViewModel pageViewModel;
private MapView map = null;
private SimpleFastPointOverlay sfpo;
private Marker marker;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getParentFragment() != null) {
pageViewModel = new ViewModelProvider(getParentFragment()).get(PageViewModel.class);
}
context = requireActivity().getApplicationContext();
}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_open_map, container, false);
LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
map = root.findViewById(R.id.mapview);
map.setTileSource(TileSourceFactory.MAPNIK);
map.setMultiTouchControls(true);
myPointsMap = new HashMap<>();
pageViewModel.getMyPoints().observe(getViewLifecycleOwner(), myPointsList -> {
myPointsMap =
myPointsList.stream().collect(Collectors.toMap(MyPoint::getId, p -> p));
if (sfpo != null) {
map.getOverlays().remove(sfpo);
}
sfpo = simpleFastPointOverlayBuilder(myPointsList);
sfpo.setOnClickListener((points, point) -> {
MyPoint mp = myPointsMap
.get(Integer.valueOf(((LabelledGeoPoint) points.get(point)).getLabel()));
if (marker != null) {
map.getOverlays().remove(marker);
}
marker = constructMarker(mp);
map.getOverlays().add(marker);
});
map.getOverlays().add(sfpo);
});
return root;
}
private SimpleFastPointOverlay simpleFastPointOverlayBuilder(List<MyPoint> myPointList) {
List<IGeoPoint> points = new ArrayList<>();
Paint textStyle = new Paint();
textStyle.setStyle(Paint.Style.FILL);
textStyle.setColor(Color.parseColor("#111111"));
textStyle.setTextAlign(Paint.Align.CENTER);
textStyle.setTextSize(24);
Paint pointStyle = new Paint();
pointStyle.setStyle(Paint.Style.FILL);
pointStyle.setColor(Color.rgb(255, 0, 0));
for(MyPoint myPoint: myPointList) {
points.add(new StyledLabelledGeoPoint(myPoint.getLocationInfo().latitude,
myPoint.getLocationInfo().longitude, Integer.toString(myPoint.getId()),
pointStyle, textStyle));
}
SimplePointTheme pointTheme = new SimplePointTheme(points);
SimpleFastPointOverlayOptions opt = SimpleFastPointOverlayOptions.getDefaultStyle()
.setSymbol(SimpleFastPointOverlayOptions.Shape.CIRCLE)
.setAlgorithm(SimpleFastPointOverlayOptions.RenderingAlgorithm.MAXIMUM_OPTIMIZATION)
.setRadius(7).setIsClickable(true).setCellSize(12)
.setMinZoomShowLabels(12);
return new SimpleFastPointOverlay(pointTheme, opt);
}
private Marker constructMarker(MyPoint l) {
GeoPoint gp = new GeoPoint(l.getLocationInfo().latitude, l.getLocationInfo().longitude);
Marker marker = new Marker(map);
marker.setPosition(gp);
CustomMarkerInfoWindow markerInfoWindow = new CustomMarkerInfoWindow(l, R.layout.marker_info_window, map);
markerInfoWindow.open(marker, gp, 0, 0);
marker.setAlpha((float) 0);
marker.setInfoWindow(markerInfoWindow);
marker.setInfoWindowAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
return marker;
}
@Override
public void onResume() {
super.onResume();
map.onResume();
}
@Override
public void onPause() {
super.onPause();
map.onPause();
}
}
最初我使用标记 class 实现了所需的功能,但是当点越来越多时性能会严重下降,所以我将 SimpleFastPointOverlay 与 PopUpwindow 结合使用。
public class OpenMapFragment extends Fragment {
private Map<Integer, MyPoint> myPointsMap;
private Context context;
private PageViewModel pageViewModel;
private MapView map = null;
private SimpleFastPointOverlay sfpo;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getParentFragment() != null) {
pageViewModel = new ViewModelProvider(getParentFragment()).get(PageViewModel.class);
}
context = requireActivity().getApplicationContext();
}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_open_map, container, false);
LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
map = root.findViewById(R.id.mapview);
map.setTileSource(TileSourceFactory.MAPNIK);
map.setMultiTouchControls(true);
myPointsMap = new HashMap<>();
pageViewModel.getMyPoints().observe(getViewLifecycleOwner(), myPointsList -> {
myPointsMap =
myPointsList.stream().collect(Collectors.toMap(MyPoint::getId, p -> p));
if (sfpo != null) {
map.getOverlays().remove(sfpo);
}
sfpo = simpleFastPointOverlayBuilder(myPointsList);
sfpo.setOnClickListener((points, point) -> {
MyPoint mp = myPointsMap
.get(Integer.valueOf(((LabelledGeoPoint) points.get(point)).getLabel()));
View popupView = inflater.inflate(R.layout.popup_window, null);
TextView txtId = popupView.findViewById(R.id.txt_id);
txtId.setText("id:" + mp.getId());
int width = LinearLayout.LayoutParams.WRAP_CONTENT;
int height = LinearLayout.LayoutParams.WRAP_CONTENT;
final PopupWindow popupWindow = new PopupWindow(popupView, width, height, true);
popupWindow.showAtLocation(getView(), Gravity.CENTER, 0, 0);
popupView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
popupWindow.dismiss();
return true;
}
});
});
map.getOverlays().add(sfpo);
});
return root;
}
private SimpleFastPointOverlay simpleFastPointOverlayBuilder(List<MyPoint> myPointList) {
List<IGeoPoint> points = new ArrayList<>();
Paint textStyle = new Paint();
textStyle.setStyle(Paint.Style.FILL);
textStyle.setColor(Color.parseColor("#111111"));
textStyle.setTextAlign(Paint.Align.CENTER);
textStyle.setTextSize(24);
Paint pointStyle = new Paint();
pointStyle.setStyle(Paint.Style.FILL);
pointStyle.setColor(Color.rgb(255, 0, 0));
for(MyPoint myPoint: myPointList) {
points.add(new StyledLabelledGeoPoint(myPoint.getLocationInfo().latitude,
myPoint.getLocationInfo().longitude, Integer.toString(myPoint.getId()),
pointStyle, textStyle));
}
SimplePointTheme pointTheme = new SimplePointTheme(points);
SimpleFastPointOverlayOptions opt = SimpleFastPointOverlayOptions.getDefaultStyle()
.setSymbol(SimpleFastPointOverlayOptions.Shape.CIRCLE)
.setAlgorithm(SimpleFastPointOverlayOptions.RenderingAlgorithm.MAXIMUM_OPTIMIZATION)
.setRadius(7).setIsClickable(true).setCellSize(12)
.setMinZoomShowLabels(12);
return new SimpleFastPointOverlay(pointTheme, opt);
}
@Override
public void onResume() {
super.onResume();
map.onResume();
}
@Override
public void onPause() {
super.onPause();
map.onPause();
}
}
虽然这是一种解决方法,但我不喜欢它,因为 popupView 位于显示的中心,并且无法与单击元素的位置相关联。有没有一种方法可以让我对 OsmDroid 的标记和信息窗口有类似的行为?
我终于找到了解决办法: 为了获得所需的功能,我应该在每次单击 simpleFastPoint 时添加一个标记,如果单击另一个标记,则删除前一个标记并添加一个新标记。所以性能仍然很好,但具有标记行为。我还让标记不可见
public class OpenMapFragment extends Fragment {
private Map<Integer, MyPoint> myPointsMap;
private Context context;
private PageViewModel pageViewModel;
private MapView map = null;
private SimpleFastPointOverlay sfpo;
private Marker marker;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getParentFragment() != null) {
pageViewModel = new ViewModelProvider(getParentFragment()).get(PageViewModel.class);
}
context = requireActivity().getApplicationContext();
}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_open_map, container, false);
LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
map = root.findViewById(R.id.mapview);
map.setTileSource(TileSourceFactory.MAPNIK);
map.setMultiTouchControls(true);
myPointsMap = new HashMap<>();
pageViewModel.getMyPoints().observe(getViewLifecycleOwner(), myPointsList -> {
myPointsMap =
myPointsList.stream().collect(Collectors.toMap(MyPoint::getId, p -> p));
if (sfpo != null) {
map.getOverlays().remove(sfpo);
}
sfpo = simpleFastPointOverlayBuilder(myPointsList);
sfpo.setOnClickListener((points, point) -> {
MyPoint mp = myPointsMap
.get(Integer.valueOf(((LabelledGeoPoint) points.get(point)).getLabel()));
if (marker != null) {
map.getOverlays().remove(marker);
}
marker = constructMarker(mp);
map.getOverlays().add(marker);
});
map.getOverlays().add(sfpo);
});
return root;
}
private SimpleFastPointOverlay simpleFastPointOverlayBuilder(List<MyPoint> myPointList) {
List<IGeoPoint> points = new ArrayList<>();
Paint textStyle = new Paint();
textStyle.setStyle(Paint.Style.FILL);
textStyle.setColor(Color.parseColor("#111111"));
textStyle.setTextAlign(Paint.Align.CENTER);
textStyle.setTextSize(24);
Paint pointStyle = new Paint();
pointStyle.setStyle(Paint.Style.FILL);
pointStyle.setColor(Color.rgb(255, 0, 0));
for(MyPoint myPoint: myPointList) {
points.add(new StyledLabelledGeoPoint(myPoint.getLocationInfo().latitude,
myPoint.getLocationInfo().longitude, Integer.toString(myPoint.getId()),
pointStyle, textStyle));
}
SimplePointTheme pointTheme = new SimplePointTheme(points);
SimpleFastPointOverlayOptions opt = SimpleFastPointOverlayOptions.getDefaultStyle()
.setSymbol(SimpleFastPointOverlayOptions.Shape.CIRCLE)
.setAlgorithm(SimpleFastPointOverlayOptions.RenderingAlgorithm.MAXIMUM_OPTIMIZATION)
.setRadius(7).setIsClickable(true).setCellSize(12)
.setMinZoomShowLabels(12);
return new SimpleFastPointOverlay(pointTheme, opt);
}
private Marker constructMarker(MyPoint l) {
GeoPoint gp = new GeoPoint(l.getLocationInfo().latitude, l.getLocationInfo().longitude);
Marker marker = new Marker(map);
marker.setPosition(gp);
CustomMarkerInfoWindow markerInfoWindow = new CustomMarkerInfoWindow(l, R.layout.marker_info_window, map);
markerInfoWindow.open(marker, gp, 0, 0);
marker.setAlpha((float) 0);
marker.setInfoWindow(markerInfoWindow);
marker.setInfoWindowAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
return marker;
}
@Override
public void onResume() {
super.onResume();
map.onResume();
}
@Override
public void onPause() {
super.onPause();
map.onPause();
}
}