Android - MapView содержится в ListView - PullRequest
11 голосов
/ 03 июня 2010

В настоящее время я пытаюсь поместить MapView в ListView. Кто-нибудь имел успех с этим? Это вообще возможно? Вот мой код:

            ListView myList = (ListView) findViewById(android.R.id.list);
        List<Map<String, Object>> groupData = new ArrayList<Map<String, Object>>();

        Map<String, Object> curGroupMap = new HashMap<String, Object>();
        groupData.add(curGroupMap);
        curGroupMap.put("ICON", R.drawable.back_icon);
        curGroupMap.put("NAME","Go Back");
        curGroupMap.put("VALUE","By clicking here");

        Iterator it = data.entrySet().iterator();
        while (it.hasNext()) 
        {
            //Get the key name and value for it
            Map.Entry pair = (Map.Entry)it.next();
            String keyName = (String) pair.getKey();
            String value = pair.getValue().toString();

            if (value != null)
            {
                //Add the parents -- aka main categories
                curGroupMap = new HashMap<String, Object>();
                groupData.add(curGroupMap);

                //Push the correct Icon
                if (keyName.equalsIgnoreCase("Phone"))
                    curGroupMap.put("ICON", R.drawable.phone_icon);
                else if (keyName.equalsIgnoreCase("Housing"))
                    curGroupMap.put("ICON", R.drawable.house_icon);
                else if (keyName.equalsIgnoreCase("Website"))
                    curGroupMap.put("ICON", R.drawable.web_icon);
                else if (keyName.equalsIgnoreCase("Area Snapshot"))
                    curGroupMap.put("ICON", R.drawable.camera_icon);
                else if (keyName.equalsIgnoreCase("Overview"))
                    curGroupMap.put("ICON", R.drawable.overview_icon);  
                else if (keyName.equalsIgnoreCase("Location"))
                    curGroupMap.put("ICON", R.drawable.map_icon);
                else
                    curGroupMap.put("ICON", R.drawable.icon);

                //Pop on the Name and Value
                curGroupMap.put("NAME", keyName);
                curGroupMap.put("VALUE", value);
            }
        }

        curGroupMap = new HashMap<String, Object>();
        groupData.add(curGroupMap);
        curGroupMap.put("ICON", R.drawable.back_icon);
        curGroupMap.put("NAME","Go Back");
        curGroupMap.put("VALUE","By clicking here");

        //Set up adapter
        mAdapter = new SimpleAdapter(
                mContext,
                groupData,
                R.layout.exp_list_parent,
                new String[] { "ICON", "NAME", "VALUE" },
                new int[] { R.id.photoAlbumImg, R.id.rowText1, R.id.rowText2  }
        );

        myList.setAdapter(mAdapter); //Bind the adapter to the list 

Заранее спасибо за помощь !!

Ответы [ 5 ]

56 голосов
/ 07 октября 2012

Чтобы опубликовать альтернативное решение для довольно старого ответа (более 2 лет), но я подумал, что это может помочь кому-то, кто может наткнуться на этот пост, как я.

ПРИМЕЧАНИЕ. Это может быть полезно для тех, кому просто нужно отобразить местоположение на «карте», но не нужно взаимодействовать с ним в ListView. Фактическая Карта может отображаться, скажем, на странице детали , после нажатия на элемент в ListView

Как уже указывалось @CaseyB, MapView является довольно тяжелым представлением. Чтобы противостоять этому аспекту (и сделать жизнь немного легче, но для меня ;-)), я решил создать URL-адрес, как вы бы сделали для статической Карты Google, используя несколько параметров, необходимых для моего приложения. Вы можете получить больше вариантов здесь: https://developers.google.com/maps/documentation/staticmaps/

Во-первых, когда я строю данные для своего ListView, я передаю такие данные, как широта и долгота в строку с некоторыми статическими переменными, взятыми из упомянутой ссылки выше. Я получаю свои координаты из API Facebook.

Код, который я использую для создания ссылки:

String getMapURL = "http://maps.googleapis.com/maps/api/staticmap?zoom=18&size=560x240&markers=size:mid|color:red|"  
+ JOLocation.getString("latitude") 
+ "," 
+ JOLocation.getString("longitude") 
+ "&sensor=false";

Приведенный выше URL при использовании в браузере возвращает файл .PNG. Затем в своем adapter для упражнения я использую Ленивая загрузка @ Fedor , чтобы отобразить изображение, сгенерированное из ранее созданного URL-адреса, для отображения в пользовательском ListView. Конечно, вы можете выбрать свой собственный метод для отображения Map (на самом деле это изображение карты).

Пример конечного результата.

enter image description here

В настоящее время у меня есть около 30 нечетных карт регистрации (я использую их вместе с Facebook SDK) в этом ListView, но у пользователей может быть 100 из них, и не было никаких сообщений о его замедлении.

Я подозреваю, что это может не помочь ОП, учитывая время, прошедшее с момента вопроса, но надеюсь, что это поможет другим пользователям, попавшим на эту страницу в будущем.

6 голосов
/ 03 июня 2010

Во-первых, я не думаю, что отображение нескольких MapView одновременно будет работать. MapActivity документирует, что для каждого процесса поддерживается только один:

"Для каждого процесса поддерживается только одна MapActivity. Несколько одновременно запущенных MapActivities могут мешать неожиданным и нежелательным образом."

(http://code.google.com/android/add-ons/google-apis/reference/index.html)

В нем прямо не сказано, что вы не можете иметь несколько MapViews в MapActivity, но я думаю, что они также будут мешать, независимо от того, в какой родительской ViewGroup они находятся.

Во-вторых, вы можете рассмотреть возможность использования API статических карт для получения простого изображения для включения в ListView - полноценный MapView в любом случае может оказаться излишне тяжелым:

http://code.google.com/apis/maps/documentation/staticmaps/

Единственная проблема, с которой вы можете столкнуться, заключается в том, что API статических карт ограничивает использование «пользователем», что, вероятно, подразумевает IP (для него не требуется ключ API), и в мобильных сетях могут возникнуть проблемы с ограничением использования IP. Я не уверен, как именно это закончится.

5 голосов
/ 03 июня 2010

В этом случае вы добавляете MapView в список, как и любой другой вид. Вот краткое руководство о том, как создать настраиваемый адаптер списка. Но я должен предупредить вас, что MapView - довольно тяжелый вид, и если вы попытаетесь вывести их на экран, вы заметите, что приложение вяло! Вы можете просто добавить кнопку в элемент списка, которая переносит пользователя на другую страницу с дополнительной информацией, включая карту.

3 голосов
/ 16 апреля 2016

Это возможно из самого кода GoogleMapSample:

/**
 * This shows to include a map in lite mode in a ListView.
 * Note the use of the view holder pattern with the
 * {@link com.google.android.gms.maps.OnMapReadyCallback}.
 */
public class LiteListDemoActivity extends AppCompatActivity {

    private ListFragment mList;

    private MapAdapter mAdapter;

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

        setContentView(R.layout.lite_list_demo);

        // Set a custom list adapter for a list of locations
        mAdapter = new MapAdapter(this, LIST_LOCATIONS);
        mList = (ListFragment) getSupportFragmentManager().findFragmentById(R.id.list);
        mList.setListAdapter(mAdapter);

        // Set a RecyclerListener to clean up MapView from ListView
        AbsListView lv = mList.getListView();
        lv.setRecyclerListener(mRecycleListener);

    }

    /**
     * Adapter that displays a title and {@link com.google.android.gms.maps.MapView} for each item.
     * The layout is defined in <code>lite_list_demo_row.xml</code>. It contains a MapView
     * that is programatically initialised in
     * {@link #getView(int, android.view.View, android.view.ViewGroup)}
     */
    private class MapAdapter extends ArrayAdapter<NamedLocation> {

        private final HashSet<MapView> mMaps = new HashSet<MapView>();

        public MapAdapter(Context context, NamedLocation[] locations) {
            super(context, R.layout.lite_list_demo_row, R.id.lite_listrow_text, locations);
        }


        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row = convertView;
            ViewHolder holder;

            // Check if a view can be reused, otherwise inflate a layout and set up the view holder
            if (row == null) {
                // Inflate view from layout file
                row = getLayoutInflater().inflate(R.layout.lite_list_demo_row, null);

                // Set up holder and assign it to the View
                holder = new ViewHolder();
                holder.mapView = (MapView) row.findViewById(R.id.lite_listrow_map);
                holder.title = (TextView) row.findViewById(R.id.lite_listrow_text);
                // Set holder as tag for row for more efficient access.
                row.setTag(holder);

                // Initialise the MapView
                holder.initializeMapView();

                // Keep track of MapView
                mMaps.add(holder.mapView);
            } else {
                // View has already been initialised, get its holder
                holder = (ViewHolder) row.getTag();
            }

            // Get the NamedLocation for this item and attach it to the MapView
            NamedLocation item = getItem(position);
            holder.mapView.setTag(item);

            // Ensure the map has been initialised by the on map ready callback in ViewHolder.
            // If it is not ready yet, it will be initialised with the NamedLocation set as its tag
            // when the callback is received.
            if (holder.map != null) {
                // The map is already ready to be used
                setMapLocation(holder.map, item);
            }

            // Set the text label for this item
            holder.title.setText(item.name);

            return row;
        }

        /**
         * Retuns the set of all initialised {@link MapView} objects.
         *
         * @return All MapViews that have been initialised programmatically by this adapter
         */
        public HashSet<MapView> getMaps() {
            return mMaps;
        }
    }

    /**
     * Displays a {@link LiteListDemoActivity.NamedLocation} on a
     * {@link com.google.android.gms.maps.GoogleMap}.
     * Adds a marker and centers the camera on the NamedLocation with the normal map type.
     */
    private static void setMapLocation(GoogleMap map, NamedLocation data) {
        // Add a marker for this item and set the camera
        map.moveCamera(CameraUpdateFactory.newLatLngZoom(data.location, 13f));
        map.addMarker(new MarkerOptions().position(data.location));

        // Set the map type back to normal.
        map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
    }

    /**
     * Holder for Views used in the {@link LiteListDemoActivity.MapAdapter}.
     * Once the  the <code>map</code> field is set, otherwise it is null.
     * When the {@link #onMapReady(com.google.android.gms.maps.GoogleMap)} callback is received and
     * the {@link com.google.android.gms.maps.GoogleMap} is ready, it stored in the {@link #map}
     * field. The map is then initialised with the NamedLocation that is stored as the tag of the
     * MapView. This ensures that the map is initialised with the latest data that it should
     * display.
     */
    class ViewHolder implements OnMapReadyCallback {

        MapView mapView;

        TextView title;

        GoogleMap map;

        @Override
        public void onMapReady(GoogleMap googleMap) {
            MapsInitializer.initialize(getApplicationContext());
            map = googleMap;
            NamedLocation data = (NamedLocation) mapView.getTag();
            if (data != null) {
                setMapLocation(map, data);
            }
        }

        /**
         * Initialises the MapView by calling its lifecycle methods.
         */
        public void initializeMapView() {
            if (mapView != null) {
                // Initialise the MapView
                mapView.onCreate(null);
                // Set the map ready callback to receive the GoogleMap object
                mapView.getMapAsync(this);
            }
        }

    }

    /**
     * RecycleListener that completely clears the {@link com.google.android.gms.maps.GoogleMap}
     * attached to a row in the ListView.
     * Sets the map type to {@link com.google.android.gms.maps.GoogleMap#MAP_TYPE_NONE} and clears
     * the map.
     */
    private AbsListView.RecyclerListener mRecycleListener = new AbsListView.RecyclerListener() {

        @Override
        public void onMovedToScrapHeap(View view) {
            ViewHolder holder = (ViewHolder) view.getTag();
            if (holder != null && holder.map != null) {
                // Clear the map and free up resources by changing the map type to none
                holder.map.clear();
                holder.map.setMapType(GoogleMap.MAP_TYPE_NONE);
            }

        }
    };

    /**
     * Location represented by a position ({@link com.google.android.gms.maps.model.LatLng} and a
     * name ({@link java.lang.String}).
     */
    private static class NamedLocation {

        public final String name;

        public final LatLng location;

        NamedLocation(String name, LatLng location) {
            this.name = name;
            this.location = location;
        }
    }
}

Полный код доступен по адресу: https://github.com/googlemaps/android-samples/blob/master/ApiDemos/app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java

0 голосов
/ 30 октября 2012

Я столкнулся с той же проблемой сегодня - получается, что вам нужно создать MapView внутри вашего MapActivity , в противном случае вы получите ошибку типа Невозможно накачать представление com.google.maps.MapView или около того ... Затем передайте этот MapView в свой ListAdapter и выкладывайте его при необходимости. Мне пришлось поместить MapView внутри RelativeLayout , чтобы настроить высоту и ширину так, как я хочу (по какой-то причине MapView не ведет себя "нормальным" способом просмотра). Вы можете запросить у меня детали, если вам нравится:)

...