Лучший способ реализовать календарь временной шкалы Android
Я хочу создать временную шкалу, как в iPhone
Время события может быть 9.42, и он должен начать рисовать ниже штриховой линии 9.30 с % от того, как далеко от 9.30.
Единственный способ, который я могу придумать, это использоватьScrollView
с FrameLayout
и программно добавлять временную шкалу.
<ScrollView
android:id="@+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
<FrameLayout
android:id="@+id/timeline"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</FrameLayout>
</ScrollView>
Может быть лучше, если я смогу использовать ListView
вместо ScrollView
, но я не знаю, как свободно разместить событие по ячейкам, потому что если событие начинается с 10.50.
Текст, который описывает это событие должно пересечь клетку.
Может ли кто-нибудь предложить меня? Спасибо.
1 ответ:
Недавно столкнулся с тем же вопросом. Я начал с вашей идеи framelayout с кучей видов сверху, но не был действительно доволен производительностью и объемом работы, которую мне нужно сделать, чтобы нарисовать и настроить, скажем, сетку под элементами.
Поэтому я решил расширить класс
View
, переопределить егоonDraw
и связанные с ним методы и просто нарисовать там все, что мне нужно.В этом случае я получаю огромное количество контроля над тем, что происходит, и как я хочу, чтобы это выглядело. Излишне говорить, что я мог бы и реализовал некоторые улучшения производительности, такие как кэширование базовой сетки в растровое изображение и тому подобное, чего довольно трудно достичь, когда вы работаете с чем-то таким высоким уровнем, как композиция макетов и представлений.
В любом случае вы или кто-то другой, у кого есть такая же проблема, возможно, захотите начать с чего-то простого, например (code is off the top of my head):
public class MyDayTimeline extends View { String [] timeMarkers; // time strings, like "9.00 AM" or something Rect [] eventRects; // a bunch of rectangles, which correspond to your events final int rowCount; final int rowHeightPx; final int firstColumnWidthPx; // ..... constructors, size and painting initialization, event position calculation and whatnot @Override protected void onDraw(Canvas canvas) { canvas.drawLine(firstColumnWidthPx, 0, firstColumnWidthPx, getMeasuredHeight(), delimeterLinesPaint); // draw a delimeter between time markers and the rest of the control space for (int i = 1; i < rowCount; i++) { canvas.drawLine(0, i * rowHeightPx, getMeasuredWidth(), i * rowHeightPx, delimeterLinesPaint); // draw a bunch of lines separating each hour } for(int i = 0; i < eventRects.size(); i++) { // draw a bunch rectangles, each representing an event canvas.drawRect(eventRects[i], eventPaintBackgroundPaint); canvas.drawRect(eventRects[i], eventPaintBorderPaint); } } }
На первый взгляд кажется, что объем работы, которую необходимо сделать, быть довольно подавляющим, но на самом деле это не так, если вы сначала планируете, что вам нужно сделать, а затем делаете это. Я пошел с чем-то вроде этого:
Начните с рисования простой сетки временной шкалы в переопределении
А затем просто продолжайте улучшать свой контроль(ы), пока вы и ваши товарищи по команде не будете довольны результатом. Очевидно, вы будете нужно постоянно тестировать, отлаживать и исправлять свой контроль на каждом шаге, поэтому иметь кучу тестовых наборов очень полезно.onDraw()
, при этом все размеры и цвета будут жестко закодированы.- переопределите
onMeasure()
иonSizeChanged()
, Начните соответственно изменять поля управления размером. Я пошел с простым определением размера, где я беру все доступное пространство по ширине и смело требую24 * rowHeightPx
по высоте, независимо от меры технические характеристики.- с ' холстом.drawText()' поместите кучу временных вех в сетку времени.
Придумайте структуру для определения ваших событий. Я пошел с начальной и конечной датой/временем, некоторой строкой темы и массивом прямоугольников. Когда размер элемента управления изменяется, я пересчитываю прямоугольники, которые должно занять каждое событие.- реализуйте рисование событий в
onDraw()
, имея предварительно определенную структуру и расчет положения на месте.- обрабатывать конкретные случаи, такие как события, охватывающие несколько дней.
- начните обрабатывать отводы с помощью
onTouchEvent()
или чего-то еще. Добавьте несколько журналов, чтобы проверить, правильно ли вы выполняете тесты на попадание, начните перерисовывать фреймы событий с выделенными цветами, если это необходимо, и все такое.- сделайте свой контроль лучше с точки зрения повторного использования. Определите геттеры и сеттеры для некоторых свойств, определите пользовательские атрибуты в
attrs.xml
, реализуйте обработку этих атрибутов в своем коде инициализации. Выставить некоторые пользовательские слушатели, как EventClickedListener или что-то в этом роде.- добавьте к этому некоторые вспомогательные элементы управления. Обернув все это в
ScrollView
, я пошел сViewPager
обрабатывать горизонтальные свайпы и показывать предыдущий/следующий день/неделю/месяц.- получив почти готовую дневную шкалу, извлеките из нее базовый класс и начните работать с другими временными шкалами, такими как неделя и месяц.
У меня также были некоторые проблемы с использованием стандартного Calendar API, когда я работал над обзорами недели и месяца, поэтому вы можете рассмотреть возможность использования других библиотек, таких как Joda Time, но это уже другая история.