Пользовательские маркеры Android MapView имеют одинаковый размер.

Я пишу приложение, которое будет отображать карту с кучей маркеров на ней. Я хочу, чтобы маркеры были динамическими (показывая на них динамический контент). Поскольку содержимое маркеров является динамическим, размер каждого маркера отличается.

Я нашел это в документации, в которой говорится, что «Разные маркеры могут быть возвращены для разных состояний. Разные маркеры могут иметь разные границы». здесь: https://developers.google.com/maps/documentation/android/reference/com/google/android/maps/OverlayItem#getMarker(int)

Я предполагаю, что это означает, что несколько маркеров на одном и том же наложении могут быть разных размеров. Это правильно?

У меня есть ArrayList на моем оверлее (расширяет BalloonItemizedOverlay). Метод createItem() оверлея выглядит следующим образом:

@Override
protected OverlayItem createItem(final int index)
{
    final Person person = people.get(index);
    final GeoPoint gp = new GeoPoint(person.getLat(), person.getLng());

    final OverlayItem oi = new OverlayItem(gp, person.getName(), person.getName());
    oi.setMarker(new PersonDrawable(defaultMarker, person));

    return oi;
}

Затем в моем PersonDrawable есть рисуемый объект с 9 патчами в качестве фонового изображения, а затем рисующий текст поверх него:

public PersonDrawable(final Drawable iBackground, final Person person)
{
    background = iBackground;
    text = person.getName();
    padding = new Rect();

    if (background instanceof NinePatchDrawable)
    {
        // This is getting hit, and just sets the value of the padding
        final NinePatchDrawable ninePatch = (NinePatchDrawable) background;
        ninePatch.getPadding(padding);
    }

    // set the bounds of the marker
    bounds = background.getBounds();

    paint = new Paint();
    paint.setColor(Color.rgb(255, 255, 255));
    paint.setFakeBoldText(true);
    paint.setTextSize(30);

    // find the bounds of the text
    final Rect textBounds = new Rect();
    paint.getTextBounds(text, 0, text.length(), textBounds);

    // set the left and right bounds to that of the text plus the padding (then center it)
    bounds.left = 0 - (textBounds.width() / 2) - padding.left;
    bounds.right = 0 + (textBounds.width() / 2) + padding.right;

    // set the bounds of the drawable
    setBounds(bounds);
}

@Override
public void draw(final Canvas canvas)
{
    // when it's time to draw, draw the background
    background.draw(canvas);
    // then draw the text within the padding
    canvas.drawText(text, bounds.left + padding.left, bounds.bottom - padding.bottom, paint);
}

Каждый маркер имеет отдельный набор границ, даже после того, как он нарисован на наложении, его границы различны. MapView (или Overlay) не использует повторно объекты из createItem(). Однако Overlay, кажется, всегда выбирает один маркер и предполагает, что это размер для всех маркеров. Это просто поведение? Есть ли что-то, что я могу сделать, чтобы он по-разному учитывал границы для каждого маркера?

Вот несколько фотографий, когда он решает выбрать маркер большего размера, все оказывается в порядке:

Росомаха длиннее, так что все выглядит нормально

Однако, когда он решает использовать меньший маркер в качестве размера:

Зверь немного короче и переполнен


person xbakesx    schedule 02.11.2012    source источник


Ответы (1)


Проблема в том, что когда Drawable загружается из ресурсов, он рассматривается как разделяемый ресурс. Из документации Drawable:

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

В OverlayItem предполагается, что Drawable будет иметь одинаковый размер повсюду. Эффект, который вы видите, заключается в том, что последняя модификация Drawable переопределяет все предыдущие модификации, поэтому все дисплеи Drawable отображаются точно так же.

Решение состоит в том, чтобы предотвратить совместное использование модификаций Drawable. Вы можете сделать это, используя метод mutate() в сочетании с несколькими загрузками Drawable из ресурса. Вы должны сделать это в сочетании с конструктором PersonDrawable, который вы описали выше.

person Nick Campion    schedule 02.11.2012
comment
Все, что говорит @Nick Campion, правда. Однако вызов mutate() не решил мою проблему. Проблема заключалась в том, что Overlay переносил одну ссылку на Drawable в качестве фона маркера. Как только я получил новый экземпляр фона для каждого маркера, размеры оказались такими, как я ожидал. В любом случае, спасибо Нику за то, что указал мне правильное направление! - person xbakesx; 03.11.2012