我正在尝试使用mapbox库及其注释插件在应用程序中进行聚类。在开发的应用程序中,必须使用单击处理程序并为每个标记设置属性(角度,图标,颜色等),因此使用SymbolLayer的选项会立即消失。我想到的唯一几乎可行的解决方案是使用SymbolManager创建一个图层,并尝试用SymbolLayer图层覆盖它(据我所知,它具有聚类功能,与SymbolManager不同,尽管这是同一件事)。该解决方案的缺点是各层的重叠是不正确的。例如,可能是簇已经出现,标记还没有消失,反之亦然。而且,簇没有与标记完全重叠。谁面对这个任务,告诉我您是如何解决的?我的解决方案如下所示。预先谢谢你!
public class MainActivity extends AppCompatActivity {
MapView mMapView;
MapboxMap mMapboxMap;
private SymbolManager symbolManager;
private List<Symbol> markers;
private CarGroup mCarData;
Style mStyle;
private static final String TAG = "MainActivity";
final Float textOffset[] = { 0f, -2.5f };
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Mapbox.getInstance(this, getString(R.string.token));
setContentView(R.layout.activity_main);
mMapView = findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
this.mMapboxMap = mapboxMap;
this.mStyle = style;
style.addImage("ic_marker", BitmapManager.generateBitmap(this, R.drawable.ic_marker), true);
style.addImage("circle", BitmapManager.generateBitmap(this, R.drawable.circle), true);
symbolManager = new SymbolManager(mMapView, mMapboxMap, style, "1");
symbolManager.setIconRotationAlignment("map");
symbolManager.setTextIgnorePlacement(true);
markers = new ArrayList<>();
handler.postDelayed(markerUpdateRunnable, 1000);
}));
}
private Runnable markerUpdateRunnable = new Runnable(){
public void run(){
if (NetworkManager.isNetWorkAvailable(MainActivity.this)) {
refreshCarData(116, "af821e21-caaa-4e09-975b-8df9ea52ef9d");
} else Toast.makeText(getApplicationContext(), "Отсутствует подключение к интернету", Toast.LENGTH_SHORT).show();
handler.postDelayed(this, 5000);
}
};
private void refreshCarData(int id, String token) {
NetworkConnector.getInstance()
.getGlonassApi()
.getCarData(id, token)
.enqueue(new Callback<CarGroup>() {
@Override
public void onResponse(@NonNull Call<CarGroup> call, @NonNull Response<CarGroup> response) {
if (response.isSuccessful()) {
refreshClusteredGeoJsonSource(response);
}
}
@Override
public void onFailure(@NonNull Call<CarGroup> call, @NonNull Throwable t) {
refreshCarData(id, token);
}
});
}
private void refreshClusteredGeoJsonSource(@NonNull Response<CarGroup> response) {
mCarData = response.body();
if (markers.size() != mCarData.getSize()) {
symbolManager.delete(markers);
}
if (symbolManager.getAnnotations().size() == 0) {
createSymbols();
} else {
moveSymbol();
}
showCluster();
}
private void moveSymbol() {
Symbol symbol;
List<Symbol> toUpdate = new ArrayList<>();
if (markers.size() == mCarData.getSize()) {
for (int i = 0; i < mCarData.getSize(); i++) {
symbol = markers.get(i);
LatLng location = mCarData.getLatLng(i);
float rotation = mCarData.getAngle(i);
final LatLng originalPosition = symbol.getLatLng();
final float originalRotation = symbol.getIconRotate();
final boolean changeLocation = originalPosition.distanceTo(location) > 0;
final boolean changeRotation = originalRotation != rotation;
if (symbolManager == null || symbolManager.getAnnotations().indexOfValue(symbol) < 0) {
return;
}
if (!changeLocation && !changeRotation) {
continue;
}
if (changeLocation) {
symbol.setLatLng(location);
}
if (changeRotation) {
symbol.setIconRotate(rotation);
}
toUpdate.add(symbol);
}
symbolManager.update(toUpdate);
}
}
private void createSymbols() {
Expression pointCount = toNumber(get("point_count"));
int[] layers = new int[] { 0, ContextCompat.getColor(this, R.color.colorAccent) } ;
for (int i = 0; i < mCarData.getSize(); i++) {
String color = ColorUtils.colorToRgbaString(ContextCompat.getColor(this, R.color.gray));
if (mCarData.isOnline(i)) {
if (mCarData.getDrive(i) == 1) {
color = ColorUtils.colorToRgbaString(ContextCompat.getColor(this, R.color.mapboxGreen));
} else {
color = ColorUtils.colorToRgbaString(ContextCompat.getColor(this, R.color.mapbox_blue));
}
}
createSymbol(mCarData.getLatLng(i), mCarData.getAngle(i), mCarData.getNumber(i), color, "ic_marker");
symbolManager.setFilter(all(has("point_count", gte(pointCount, literal(layers[0])))));
}
}
private void createSymbol(LatLng latLng, float angle, String number, String color,@Nullable String icon) {
SymbolOptions symbolOptions = new SymbolOptions()
.withLatLng(latLng)
.withIconImage(icon)
.withIconSize(0.8f)
.withTextField(number)
.withTextSize(10.0f)
.withTextOffset(textOffset)
.withTextHaloColor(ColorUtils.colorToRgbaString(Color.WHITE))
.withTextHaloWidth(1f)
.withIconColor(color)
.withIconRotate(angle)
.withZIndex(0)
.setDraggable(false);
markers.add(symbolManager.create(symbolOptions));
}
private void showCluster() {
List<Feature> markerCoordinates = new ArrayList<>();
for(int i = 0; i < mCarData.getSize(); i++) {
markerCoordinates.add(Feature.fromGeometry(
Point.fromLngLat(mCarData.getLon(i), mCarData.getLat(i))));
}
GeoJsonSource mSource = (GeoJsonSource) mStyle.getSource("markers");
if (mSource == null) {
mStyle.addSource(
new GeoJsonSource("markers",
FeatureCollection.fromFeatures(markerCoordinates),
new GeoJsonOptions()
.withCluster(true)
.withTolerance(0.5f)
.withClusterRadius(50)
.withClusterMaxZoom(14)
)
);
} else {
mSource.setGeoJson(FeatureCollection.fromFeatures(markerCoordinates));
}
int[] layers = new int[] { 0, ContextCompat.getColor(this, R.color.mapbox_blue) } ;
for (int i = 0; i < layers.length; i++) {
//Add clusters' circles
CircleLayer circles = (CircleLayer) mStyle.getLayer("cluster-" + i);
if (circles == null) {
circles = new CircleLayer("cluster-" + i, "markers");
circles.setProperties(
circleColor(layers[1]),
circleRadius(18f)
);
Expression pointCount = toNumber(get("point_count"));
// Add a filter to the cluster layer that hides the circles based on "point_count"
circles.setFilter(all(has("point_count"), gte(pointCount, literal(layers[0]))));
mStyle.addLayer(circles);
}
}
//Add the count labels
SymbolLayer count = (SymbolLayer) mStyle.getLayer("count");
if (count == null) {
count = new SymbolLayer("count", "markers");
count.setProperties(
textField(Expression.toString(get("point_count"))),
textSize(12f),
textColor(Color.WHITE),
textIgnorePlacement(true),
textAllowOverlap(true)
);
mStyle.addLayer(count);
}
}
@Override
public void onStart() {
super.onStart();
mMapView.onStart();
}
@Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
@Override
public void onStop() {
super.onStop();
mMapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mMapView.onSaveInstanceState(outState);
}
}