Мне нравится Dribbble. Там есть много крутых и вдохновляющих дизайн-проектов. Но если вы разработчик, то часто чувство прекрасного быстро сменяется на отчаяние, когда вы начинаете думать о том, как реализовать этот крутой дизайн. В этой статье я покажу вам пример такого дизайна и его реализацию, но перед этим давайте поговорим о решении проблемы в целом. Самый простой способ — использовать какую-то библиотеку, закрывающую наши потребности. Теперь не поймите меня неправильно, я большой сторонник подхода «не изобретать велосипед». Есть отличные библиотеки с открытым исходным кодом, и когда мне будет нужно загружать изображения или реализовывать REST API, Glide/Picasso и Retrofit очень здорово помогут мне. Но когда вам нужно реализовать какой-то необычный дизайн, это не всегда лучший выбор. Вам нужно будет потратить время на поиск хорошей, поддерживаемой библиотеки, которая будет делать что-то подобное. Затем вам нужно заглянуть в код, чтобы убедиться, что там написано что-то адекватное. Вам нужно будет уделить больше времени пониманию настроек и конфигураций, которыми вы сможете управлять для использования библиотеки в ваших задачах. И давайте будем честными, скорее всего, библиотека не покроет ваших нужд на 100%, и вам нужно будет пойти на некоторые компромиссы с дизайнерами. Поэтому я говорю о том, что зачастую проще и лучше создать свой собственный View-компонент. Когда я говорю «собственный View-компонент», я имею в виду расширение класса View, переопределение метода onDraw() и использование Paint и Canvas для рисования View-компонента. Это может показаться страшным, если вы не делали этого раньше, потому что у этих классов есть много методов и свойств, но вы можете сосредоточиться на основных: canvas.drawRect() — укажите координаты углов и нарисуете прямоугольник; canvas.drawRoundRect() — дополнительно укажите радиус, и углы прямоугольника будут закруглены; canvas.drawPath() — это более сложный, но и более мощный способ создания собственной фигуры с помощью линий и кривых; canvas.drawText() — для рисования текста на канвасе (с помощью Paint вы сможете контролировать размер, цвет и другие свойства); canvas.drawCircle() — укажите центральную точку и радиус и получится круг; canvas.drawArc() — укажите ограничивающий прямоугольник, а также начальный и поворотный углы для рисования дуги; paint.style — указывает, будет ли нарисованная фигура заполнена, обведена или и то, и другое; paint.color — указывает цвет (включая прозрачность); paint.strokeWidth — управляет шириной для обводки фигур; paint.pathEffect — позволяет влиять на геометрию рисуемой фигуры; paint.shader — позволяет рисовать градиенты. Помните, иногда вам может понадобиться использовать другие API, но даже овладев этими методами, вы сможете рисовать очень сложные фигуры. Вот такой дизайн предлагает нам Pepper:  Здесь много чего интересного, но давайте разберём всё на мелкие кусочки. Мы находим минимальное и максимальное значения, вычисляем соотношение пикселей на единицу, размер шага по горизонтали между маркерами и позиции X и Y.  Мы создаем фигуру, начиная с левого края, проводя линию между каждым маркером и завершая фигуру в начальной точке. Затем рисуем эту фигуру, используя краску с градиентным шейдером.  Мы настраиваем краску, чтобы она рисовала пунктиром. Затем мы используем специальный цикл языка Kotlin, который позволяет нам перебирать маркеры с шагом 7 (количество дней в неделе). Для каждого маркера мы берём координату X и рисуем вертикальную пунктирную линию от вершины графика до zeroY.  Мы перебираем маркеры, рисуем для каждого из них закрашенный круг и простую линию от предыдущего маркера до текущего.  Мы перебираем метки недель, находим координату X середины недели и начинаем рисовать кнопку по слоям: сначала рисуем фон с закругленными углами, затем границу и, наконец, текст. Мы настраиваем краску перед рисованием каждого слоя.  Координата X — это позиция последнего маркера плюс некоторый отступ. Координата Y рассчитывается с использованием соотношения пикселей на единицу. Мы форматируем число в строку (при необходимости добавляем разделитель тысяч) и рисуем текст. Вот и всё, теперь наш onDraw() будет выглядеть так: И объединение слоёв даст нам желаемый результат:  Что касается последнего пункта, для меня это один из лучших уроков программирования в целом: когда сталкиваетесь с большой и сложной задачей, разбейте её на более мелкие, более простые задачи. Образовательная IT-академия