Android карты Utils кластеризация показать InfoWindow


Я планирую использовать маркерную кластеризацию google maps, доступную в библиотеке utils, но приложение Google example показывает только маркерные кластеры без какого-либо infoWindow. Мне вот интересно, я не смогла показать InfoWindow? Я хочу, чтобы информационное окно отображалось на маркере, как при обычном маркере google maps, а не на кластере.

Код у меня есть: (из примера google)

public class BigClusteringDemoActivity extends FragmentActivity {
    private ClusterManager<MyItem> mClusterManager;
    private GoogleMap mMap;

    private void readItems() {
        InputStream inputStream = getResources().openRawResource(R.raw.radar_search);
        List<MyItem> items = new MyItemReader().read(inputStream);

        for (int i = 0; i < 10; i++) {
            double offset = i / 60d;
            for (MyItem item : items) {
                LatLng position = item.getPosition();
                double lat = position.latitude + offset;
                double lng = position.longitude + offset;
                MyItem offsetItem = new MyItem(lat, lng);
                mClusterManager.addItem(offsetItem);
            }
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map);

        mClusterManager = new ClusterManager<>(this, mMap);

        mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();

        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.503186, -0.126446), 10));
        mMap.setOnCameraChangeListener(mClusterManager);

        readItems();
    }

}
3 9

3 ответа:

Вот упрощенное и слегка модифицированное решение, основанное наэтом ответе . Обратите внимание, что связанный ответ реализует InfoWindow как для маркеров, так и для кластеров.

Это решение реализует только InfoWindows для маркеров.

Это похоже на то, как вы бы реализовали пользовательский InfoWindowAdapter для обычных маркеров без кластеризации, но с дополнительным требованием, чтобы вы сохраняли ссылку на текущий выбранный элемент, чтобы вы могли получить заголовок и Фрагмент из его экземпляра MyItem, так как маркер не хранит заголовок и фрагмент, как это обычно делается.

Обратите внимание, что поскольку все данные хранятся в ссылках MyItem, гораздо проще расширить функциональность, чтобы отобразить столько типов данных, сколько вы хотите в окне InfoWindow для каждого маркера.

Во-первых, MyItem.java, которая включает дополнительные поля для заголовка и сниппета:

public class MyItem implements ClusterItem {
    private final LatLng mPosition;
    private final String mTitle;
    private final String mSnippet;

    public MyItem(double lat, double lng, String t, String s) {
        mPosition = new LatLng(lat, lng);
        mTitle = t;
        mSnippet = s;
    }

    @Override
    public LatLng getPosition() {
        return mPosition;
    }

    public String getTitle(){
        return mTitle;
    }

    public String getSnippet(){
        return mSnippet;
    }
}

Вот полный класс Activity, который включает в себя все функции для поддержки Информационные окна для каждого маркера, добавленного с помощью библиотеки кластеров:

Edit: добавлена поддержка обработки событий click в InfoWindow, реализована реализация действия OnClusterItemInfoWindowClickListener и добавлен обратный вызов onClusterItemInfoWindowClick.

public class MapsActivity extends AppCompatActivity
        implements ClusterManager.OnClusterItemInfoWindowClickListener<MyItem> {

    private ClusterManager<MyItem> mClusterManager;
    private MyItem clickedClusterItem;
    private GoogleMap mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_maps);

        setUpMapIfNeeded();
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();
    }


    private void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the map.
        if (mMap == null) {
            // Try to obtain the map from the SupportMapFragment.
            mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
                    .getMap();

            // Check if we were successful in obtaining the map.
            if (mMap != null) {
                setUpMap();
            }

        }
    }

    private void setUpMap() {

        mMap.getUiSettings().setMapToolbarEnabled(true);
        mMap.getUiSettings().setZoomControlsEnabled(true);
        mMap.setMyLocationEnabled(true);
        mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);

        mClusterManager = new ClusterManager<>(this, mMap);

        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.779977,-122.413742), 10));

        mMap.setOnCameraChangeListener(mClusterManager);
        mMap.setOnMarkerClickListener(mClusterManager);

        mMap.setInfoWindowAdapter(mClusterManager.getMarkerManager());

        mMap.setOnInfoWindowClickListener(mClusterManager); //added
        mClusterManager.setOnClusterItemInfoWindowClickListener(this); //added

        mClusterManager
                .setOnClusterItemClickListener(new ClusterManager.OnClusterItemClickListener<MyItem>() {
                    @Override
                    public boolean onClusterItemClick(MyItem item) {
                        clickedClusterItem = item;
                        return false;
                    }
                });



        addItems();

        mClusterManager.getMarkerCollection().setOnInfoWindowAdapter(
                new MyCustomAdapterForItems());

    }

    private void addItems() {

        double latitude = 37.779977;
        double longitude = -122.413742;
        for (int i = 0; i < 10; i++) {
            double offset = i / 60d;

            double lat = latitude + offset;
            double lng = longitude + offset;
            MyItem offsetItem = new MyItem(lat, lng, "title " + i+1, "snippet " + i+1);
            mClusterManager.addItem(offsetItem);

        }

    }

    //added with edit
    @Override
    public void onClusterItemInfoWindowClick(MyItem myItem) {

        //Cluster item InfoWindow clicked, set title as action
        Intent i = new Intent(this, OtherActivity.class);
        i.setAction(myItem.getTitle());
        startActivity(i);

        //You may want to do different things for each InfoWindow:
        if (myItem.getTitle().equals("some title")){

            //do something specific to this InfoWindow....

        }

    }

    public class MyCustomAdapterForItems implements GoogleMap.InfoWindowAdapter {

        private final View myContentsView;

        MyCustomAdapterForItems() {
            myContentsView = getLayoutInflater().inflate(
                    R.layout.info_window, null);
        }
        @Override
        public View getInfoWindow(Marker marker) {

            TextView tvTitle = ((TextView) myContentsView
                    .findViewById(R.id.txtTitle));
            TextView tvSnippet = ((TextView) myContentsView
                    .findViewById(R.id.txtSnippet));

            tvTitle.setText(clickedClusterItem.getTitle());
            tvSnippet.setText(clickedClusterItem.getSnippet());

            return myContentsView;
        }

        @Override
        public View getInfoContents(Marker marker) {
            return null;
        }
    }
}

Info_window.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    android:orientation="vertical"
    android:background="#000000">

    <TextView
        android:id="@+id/txtTitle"
        android:textColor="#D3649F"
        android:textStyle="bold"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/txtSnippet"
        android:textColor="#D3649F"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

Результат:

Начальный запуск:

Введите описание изображения здесь

Уменьшение масштаба, начинается кластеризация:

Введите описание изображения здесь

Масштабирование снова, больше кластеризации:

Введите описание изображения здесь

Затем увеличьте масштаб и нажмите кнопку на отдельном маркере:

Введите описание изображения здесь

Затем щелчок по другому маркеру:

Введите описание изображения здесь

Edit: чтобы показать "речевой пузырь" вокруг пользовательского InfoWindow, используйте getInfoContents() вместо getInfoWindow():

public class MyCustomAdapterForItems implements GoogleMap.InfoWindowAdapter {

    private final View myContentsView;

    MyCustomAdapterForItems() {
        myContentsView = getLayoutInflater().inflate(
                R.layout.info_window, null);
    }

    @Override
    public View getInfoWindow(Marker marker) {
        return null;
    }

    @Override
    public View getInfoContents(Marker marker) {

        TextView tvTitle = ((TextView) myContentsView
                .findViewById(R.id.txtTitle));
        TextView tvSnippet = ((TextView) myContentsView
                .findViewById(R.id.txtSnippet));

        tvTitle.setText(clickedClusterItem.getTitle());
        tvSnippet.setText(clickedClusterItem.getSnippet());

        return myContentsView;
    }
}

Результат:

Введите описание изображения здесь

  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map);

        mClusterManager = new ClusterManager<>(this, mMap);

        mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();

        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.503186, -0.126446), 10));
        mMap.setOnCameraChangeListener(mClusterManager);
        mMap.setInfoWindowAdapter(new InfoWindowAdapter() {
        /**
         * View for displaying marker popup, if null default framework view would be used
         */
        @Override
        public View getInfoWindow(Marker marker) {
            return null;
        }

        /**
         * For changing the content of infowindow
         * Called when showMarkerInfo method is called
         */
        @Override
        public View getInfoContents(Marker marker) {
            View v = getLayoutInflater().inflate(R.layout.view_to_inflate, null);      
            //code for initializing view part
            return v;
        }
    });
        readItems();
    }

Можно рассмотреть следующий подход:

public void initilizeMap() {
            googleMap = mFragment.getMap();
            googleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
            googleMap.getUiSettings().setZoomControlsEnabled(true`enter code here`); // true to`enter code here`
            googleMap.getUiSettings().setZoomGesturesEnabled(true);
            googleMap.getUiSettings().setCompassEnabled(true);
            googleMap.getUiSettings().setMyLocationButtonEnabled(true);
            googleMap.getUiSettings().setRotateGesturesEnabled(true);
            if (googleMap == null) {
                Toast.makeText(getActivity(), "Sorry! unable to create maps",
                        Toast.LENGTH_SHORT).show();
            }
            mClusterManager = new ClusterManager<MyItem>(getActivity(),   googleMap );
//          googleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter());
            googleMap.setOnMapLoadedCallback(this);
            googleMap.setMyLocationEnabled(true);
            googleMap.setBuildingsEnabled(true);
            googleMap.getUiSettings().setTiltGesturesEnabled(true);

MyItem offsetItem = new MyItem(Double.parseDouble(outletList.get(i).getMap_latitude()),
                                           Double.parseDouble(outletList.get(i).getMap_longitude()), title , address);
            mClusterManager.addItem(offsetItem);
            googleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter(offsetItem));

}


    private class CustomInfoWindowAdapter implements InfoWindowAdapter {
        Marker marker;
        private View view;
        private MyItem items;

        public CustomInfoWindowAdapter(MyItem item) {
            view = getActivity().getLayoutInflater().inflate(
                    R.layout.custom_info_window, null);
            this.items = item;
        }

        @Override
        public View getInfoContents(Marker marker) {

            if (marker != null && marker.isInfoWindowShown()) {
                marker.hideInfoWindow();
                marker.showInfoWindow();
            }
            return null;
        }

        @Override
        public View getInfoWindow(final Marker marker) {
            this.marker = marker;

            String url = null;

            if (marker.getId() != null && markers != null && markers.size() > 0) {
                if (markers.get(marker.getId()) != null
                        && markers.get(marker.getId()) != null) {
                    url = markers.get(marker.getId());
                }
            }

            final ImageView image = ((ImageView) view.findViewById(R.id.badge));

            if (url != null && !url.equalsIgnoreCase("null")
                    && !url.equalsIgnoreCase("")) {
                imageLoader.displayImage(url, image, options,
                        new SimpleImageLoadingListener() {
                            @Override
                            public void onLoadingComplete(String imageUri,
                                    View view, Bitmap loadedImage) {
                                super.onLoadingComplete(imageUri, view,
                                        loadedImage);
                                getInfoContents(marker);
                            }
                        });
            } else {
                image.setImageResource(R.drawable.ic_launcher);
            }

            final String title = items.getTitle();
            Log.e(TAG, "TITLE : "+title);
            final TextView titleUi = ((TextView) view.findViewById(R.id.title));
            if (title != null) {
                titleUi.setText(title);
            } else {
                titleUi.setText("");
            }

            final String address = items.getAddress();
            final TextView snippetUi = ((TextView) view
                    .findViewById(R.id.snippet));
            if (address != null) {
                snippetUi.setText(address);
            } else {
                snippetUi.setText("");
            }