Лучший способ реализовать календарь временной шкалы 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 2

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(), при этом все размеры и цвета будут жестко закодированы.
  1. переопределите onMeasure() и onSizeChanged(), Начните соответственно изменять поля управления размером. Я пошел с простым определением размера, где я беру все доступное пространство по ширине и смело требую 24 * rowHeightPx по высоте, независимо от меры технические характеристики.
  2. с ' холстом.drawText()' поместите кучу временных вех в сетку времени.
  3. Придумайте структуру для определения ваших событий. Я пошел с начальной и конечной датой/временем, некоторой строкой темы и массивом прямоугольников. Когда размер элемента управления изменяется, я пересчитываю прямоугольники, которые должно занять каждое событие.
  4. реализуйте рисование событий в onDraw(), имея предварительно определенную структуру и расчет положения на месте.
  5. обрабатывать конкретные случаи, такие как события, охватывающие несколько дней.
  6. начните обрабатывать отводы с помощью onTouchEvent() или чего-то еще. Добавьте несколько журналов, чтобы проверить, правильно ли вы выполняете тесты на попадание, начните перерисовывать фреймы событий с выделенными цветами, если это необходимо, и все такое.
  7. сделайте свой контроль лучше с точки зрения повторного использования. Определите геттеры и сеттеры для некоторых свойств, определите пользовательские атрибуты в attrs.xml, реализуйте обработку этих атрибутов в своем коде инициализации. Выставить некоторые пользовательские слушатели, как EventClickedListener или что-то в этом роде.
  8. добавьте к этому некоторые вспомогательные элементы управления. Обернув все это в ScrollView, я пошел с ViewPager обрабатывать горизонтальные свайпы и показывать предыдущий/следующий день/неделю/месяц.
  9. получив почти готовую дневную шкалу, извлеките из нее базовый класс и начните работать с другими временными шкалами, такими как неделя и месяц.
А затем просто продолжайте улучшать свой контроль(ы), пока вы и ваши товарищи по команде не будете довольны результатом. Очевидно, вы будете нужно постоянно тестировать, отлаживать и исправлять свой контроль на каждом шаге, поэтому иметь кучу тестовых наборов очень полезно.

У меня также были некоторые проблемы с использованием стандартного Calendar API, когда я работал над обзорами недели и месяца, поэтому вы можете рассмотреть возможность использования других библиотек, таких как Joda Time, но это уже другая история.