Маркер строки ListView ala GMail

#android #android-layout #android-listview #android-3.0-honeycomb #android-fragments

#Android #android-макет #android-listview #android-3.0-honeycomb #android-фрагменты

Вопрос:

Я заинтересован в создании ListView, где каждая строка помечена так, как это сделано в GMail для версии 3.0 . Это создает хорошее разделение левого и правого фрагментов списка.

Другие примеры включают также Календарь Google на 2.3.4, например, где цветной маркер находится слева от ListView.

Просмотр списка GMail

Посмотрите на серый вертикальный разделитель между двумя списками. Как достичь чего-то подобного? Бонусом была бы также переменная ширина, но я думаю, что это всего лишь меньшее изменение макета.

Я знаю, что, вероятно, мог бы сделать что-то вроде вставки ImageView туда, а затем залить его цветом, который я хотел бы, но мне кажется, что это уродливый взлом.

Другой вопрос был бы также в том, существует ли обобщенный способ каким-либо образом объединить два фрагмента ListView, как это делают приложения GMail или Mail.

Просмотр списка GMail в двух фрагментах

Ответ №1:

Если вам нужна скорость, то я бы предпочел использовать пользовательский класс просмотра (например, extend RelativeLayout ) для представления контейнера строк и переопределить dispatchDraw(Canvas canvas) метод.

dispatchDraw Метод вызывается после отображения собственного содержимого и перед отображением дочерних элементов — дочерние элементы отображаются при вызове super.dispatchDraw .

Используйте это, чтобы сделать что-то вроде

 private boolean mDrawMarker = false;

public void setShouldDrawMarker(boolean drawMarker) {
    mDrawMarker = drawMarker;
}
public boolean getShouldDrawMarker() {
    return mDrawMarker;
}

@Override
public void dispatchDraw(Canvas canvas) {
    // draw the children of our view 
    super.dispatchDraw(canvas);

    // draw our marker on top of the children if needed
    if (mDrawMarker) {
        // e.g. canvas.drawRect(...) or canvas.drawBitmap(...)
    }
}
  

Таким образом, вы избегаете добавления каких-либо дополнительных представлений в иерархию, что означает, что вы не понесете никаких штрафных санкций на этапах компоновки или измерения. Не забудьте повторно использовать объекты Paint и Rect , если рисуете прямоугольник, а не создаете каждый раз новый. Аналогично, если вы используете bitmap, вы должны использовать один и тот же экземпляр Bitmap во всех экземплярах вашего представления, а не загружать каждый раз новый из ваших ресурсов (это не означает размещение их в static полях)

Для отступов элементов, поскольку в этом случае списки, похоже, не перекрываются, вы могли бы (с моей точки зрения):

  • Установите левое поле в контейнере строк (не совсем уверен, что это сработает)
  • Оберните контейнер строк в LinearLayout и установите для этого левое заполнение (если вышеупомянутое не работает)
  • Используйте пользовательский класс просмотра (если установка левого поля не работает)
  • Воспользуйтесь предложением @commonsware и используйте два вида — один слева с серым цветом фона, а другой справа от него с цветом маркера — затем просто установите вид слева на видимый / отсутствующий, если вы хотите, чтобы отступ / без отступа

Что касается перекрытия представлений во втором примере, я отложу ответ на @commonsware.

Ответ №2:

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

Вот 2 метода:

1 — Использование StateListDrawable для фона строки:

Если это так, я бы создал файл макета строки списка и установил для свойства «background» значение StateListDrawable (может быть XML). Это позволит строке переключать визуальные состояния для выбранного и невыбранного.

Атрибутом «drawable» для StateListDrawable будет формат PNG с 9 вставками, один для невыбранного состояния, в котором нет полей, и один для выбранного… выбранный будет определять поле внутри самого PNG, указывая, что область содержимого / нижняя черная линия не распространяется полностью на левую часть PNG, оставляя область, которая является вашим ненамасштабированным полем.

Для удобства людей, которые находят это, Рэдли Маркс только что опубликовал отличный пост в обновлении 9:http://radleymarx.com/blog/simple-guide-to-9-patch

В ListViews иногда бывает так, что вы хотите отключить «listSelector» (который представляет собой отдельный объект, отображаемый либо над списком, либо позади) и вместо этого использовать атрибут «duplicateParentState», чтобы разрешить самой строке отображать выделение (выбор списка не требуется). Это может предоставить немного больше свободы творчества, особенно если вы хотите иметь поля переменной ширины в определенных строках или несколько типов строк, которые выглядят по-разному. Хотя это полностью зависит от дизайна.

2 — Использование поля для каждой строки:

Если вы решили, что вам нужно несколько типов цветовых индикаторов и так далее, возможно, вам придется использовать другой подход, предоставляя атрибут margin (который, вероятно, не будет работать сразу)… Это относится к тому, как LayoutParams используются системой компоновки. Я пытаюсь вспомнить точные детали, но я думаю, что это связано с различными типами подкласса LayoutParam, а свойства MarginLayoutParam (или подкласса этого), например, marginLeft, могут игнорироваться кодом макета ListView. Вы должны использовать экземпляр AbsListView.LayoutParams, который не включает в себя параметры полей. Один из способов — вложить вашу строку в представление контейнера (подкласс), который допускает поля в своих параметрах LayoutParams *. Я уверен, что в конечном итоге я не делал этого постороннего вложения, но мне придется покопаться в некотором коде, чтобы вспомнить лучшее решение.

Вы упоминаете, что помещаете ImageView и заполняете его цветом. Есть пара альтернатив, на которые вы могли бы обратить внимание… Вероятно, наиболее эффективным было бы определить свой собственный класс ListRow и использовать onDraw (), чтобы фактически нарисовать содержимое строки самостоятельно, canvas.draw_xyz(), чтобы нарисовать маленькую цветную вкладку и нарисовать текст и т.д. Для всего остального, А не создавать строку в составном макете. Второй способ использования макетов заключался бы в том, чтобы иметь более легкий <View layout_height=»match_parent» layout_width=»4dip» background = «#ffff0000» /> например.

* Золотое правило верстки Android: сложная иерархия пользовательского интерфейса снижает производительность, особенно в таких приложениях, как ListView. Часто этого можно избежать, используя другие вещи: RelativeLayout, drawableTop (etc), изображения с 9 исправлениями, Вместо добавления дополнительных просмотров.

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

Ответ №3:

Как достичь чего-то подобного?

Сразу скажу, я бы использовал a View с желаемым цветом фона, видимым, когда вы этого хотите, и невидимым, когда вы этого не хотите.

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

Я не знаю, что вы подразумеваете под «переменной шириной». Я думаю, что есть два, Views с желаемым цветом фона по горизонтали LinearLayout , при этом виден только один.

Я знаю, что, вероятно, мог бы сделать что-то вроде вставки ImageView туда, а затем залить его цветом, который я хотел бы, но мне кажется, что это уродливый взлом.

Ну, ImageView это немного тяжелее, чем необходимо. В противном случае я не понимаю, почему это взлом. Думайте о них как о значках, которые просто бывают высокими, тонкими, серыми и не всегда нужны.

Другой вопрос был бы также в том, существует ли обобщенный способ каким-либо образом объединить два фрагмента ListView, как это делают приложения GMail или Mail.

Используйте RelativeLayout , чтобы правый фрагмент мог располагаться поверх левого фрагмента.

Комментарии:

1. Значит, этот белый маркер является частью правого фрагмента и просто рисуется поверх левого? Что также означает, что в этом случае я должен синхронизировать рисование правого с положением прокрутки левого.

2. Спасибо за подсказку. На самом деле, если вы выберете самый верхний элемент и прокрутите его до самого верха, вы увидите, что белый маркер исчезает. Он является частью левого фрагмента и нарисован поверх правого.

3. @Joa Ebert: «Значит, этот белый маркер является частью правого фрагмента и просто рисуется поверх левого?» — это один из подходов. Я запустил свой XOOM и более внимательно посмотрел на пользовательский интерфейс в реальном времени, в отличие от вашего фрагмента скриншота. Если вертикальная серая линия, разделяющая два фрагмента, является частью ListFragment слева, то наконечник стрелки также может быть частью этого фрагмента, как часть выбранной строки.