Android custom view padding

Новый View компонент

Иногда расширения стандартного View класса не достаточно чтобы решить требуемую задачу и вам придется рисовать содержимое view компонента самостоятельно. В этом руководстве мы создадим view, который рисует график , используя класс Canvas, а также немного изучим как работает view dimensions и padding .

Если вы к этому еще не готовы, прочитайте предыдущую часть.

Рисуем первые пиксели

Если вы хотите нарисовать в custom view что-то свое, лучше всего просто расширить класс View. Это самый базовый блок пользовательского интерфейса (UI) и также полностью функциональный класс, хотя кое-чего в нем не хватает.

Итак, мы начнем с создания нового класса, который расширяет класс View.

Чтобы нарисовать первые пиксели, нам нужно просто переопределить метод onDraw(), в этом методе мы получаем объект canvas, который можно использовать для рисования. В данном случае нам не нужно вызывать onDraw() метод суперкласса, потому что для класса View этот метод просто пустой.

Этот код рисует голубую линию толщиной 4 пикселя, которая начинается в точке (0, 0) и заканчивается в точке (getWidth(), getHeight()). Класс Paint определяет каким образом все это рисуется. Хотя объект paint позволяет создавать достаточно много интересных эффектов, здесь он используется только для установки цвета и стиля рисования.

Обратите внимание, при рисовании верхняя левая часть view — это (0, 0), независимо от того, где view находится на экране. View класс имеет методы getLeft() и getTop(), но они возвращают позицию view относительно родительского view, поэтому их не следует использовать при рисовании.

Итак, мы создали свой собственный view, который рисует линию. Это не слишком полезно, но мы по крайней мере с чего то начали.

Добавляем padding

Когда вы создаете XML layout, вы наверняка используете в различных view такой параметр как padding. Однако, если вы попытаетесь использовать padding для view, который мы только что создали, вы увидите, что это не работает. Это связано с тем, что мы не учли его при рисовании.

Все довольно просто, padding входит в ширину нашего view. Если view шириной 100 пикселей, а padding по 10 пикселей с обоих сторон, тогда ширина, доступная для рисования, составит 80 пикселей (то же самое, конечно, применимо и к высоте). Когда мы используем функцию getWidth(), то получаем ширину, включающую padding. Используя методы getPaddingTop(), getPaddingBottom(), getPaddingLeft() и getPaddingRight() мы можем получить величину padding.

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

Измененный onDraw() метод будет выглядеть так:

Теперь изменения параметра padding в XML файле будут иметь должный эффект.

Я установил темно серый цвет фона view. Как видно из рисунка, фон отображается на весь view и даже за пределами padding. Это нормальное поведение.

Необходимость поддержки параметра — padding зависит от того, как вы планируете использовать ваш view. Тем не менее, я настоятельно рекомендую вам добавить поддержку параметра padding в самом начале, даже если вы думаете, что это вам не понадобится. Добавлять padding к более сложному view компоненту, например, который имеет множество деталей и обрабатывает нажатия, может быть довольно утомительным. Поэтому решив эту задачу в самом начале, вы облегчите себе дальнейшую работы.

Рисуем линейный график

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

Эта функция позволит пользователю view задавать данные для отображения. Для каждой точки на графике нам нужно два значения — X и Y. Но если мы зададим X координаты как равноудаленные отрезки, то можно использовать X как индекс массива, а Y как значения массива.

Чтобы правильно отображать данные, нам нужно их масштабировать, иначе они могут не поместиться в размер view. Для масштабирования значений будет использоваться следующий метод.

Читайте также:  Facebook для андроид последняя версия

Метод получает два значения — текущую Y координату и максимальное значение среди всех данных. Первое, что нужно сделать — выполнить масштабирование. Обратите внимание, при вычислении высоты мы учитываем padding и сверху, и снизу.

Далее мы инвертируем полученное значение. Для чего это надо? На дисплее большему значению Y соответствуют точки, которые расположены в нижней части, но для нашего графика наивысшая Y координата должна быть вверху (прим.: у дисплея Y ось направлена вниз). После инвертирования мы добавляем смещение и возвращаем вычисленное значение.

Функция для вычисления максимального значения Y я приводить не буду. Она очевидна, нужно просто перебрать массив и найти максимум.

Для X координаты нам тоже понадобится функция масштабирования.

Теперь мы готовы нарисовать график. Мы можем рисовать линии между точками, но лучше решить эту задачу по-другому, используя класс Path. Визуальной разницы никакой не будет, но это упростит нам написание кода. Метод onDraw() теперь будет выглядеть так:

В первой части кода мы конструируем объект path, используя созданный ранее метод getYPos(). Также там используется метод getXPos(), который работает аналогичным образом, только не инвертирует значения. Создание path начинается с инициализации начальной точкой. Далее мы продлеваем path, добавляя следующие точки.

Вторая часть кода делает почти то же самое, что и раньше, только вместо метода drawLine() мы используем drawPath().

Результат (для каких-то произвольных данных) будет выглядеть так.

Это уже похоже на линейный график. Пришло время добавить еще несколько деталей.

Добавляем детали

Первая вещь, которую мы добавим — это сглаживание (anti aliasing). Это уменьшит угловатость и зазубренность линий при рисовании. Сглаживание контролируется объектом paint и его можно включить так.

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

Теперь все что мы нарисуем, используя paint, будет отбрасывать тени. Первый аргумент функции задает радиус размытия тени. Большее значение задает большее размытие (blur). Если установить этот аргумент 0, теневой слой будет удален. Следующие два аргумента задают смещение тени. В нашем случае тень будет смещена на 2 пикселя вправо и вниз. И последний аргумент — цвет тени и прозрачность. В данном случае установлен черный цвет и половинная прозрачность (на картинке эффект почти не заметен, но на эмуляторе его отчетливо видно).

Рисунок ниже — это результат дальнейшей доработки view компонента. Я добавил на фон горизонтальные линии, чтобы view был больше похож на график. Для рисования линий я использовал дополнительную функцию, чтобы понимать, где и в каком количестве отображать эти линии, но для данной статьи это не очень важно.

Итак, мы добавили достаточно много вещей в наш view, чтобы он выглядел подходящим образом. Используя canvas мы можем рисовать линии, пути(paths), прямоугольники, овалы, растровые изображения и так далее. Используя объект paint мы также можем менять стиль, цвет, ширину, эффекты и другие параметры. Я рекомендую вам почитать документацию на классы Canvas и Paint и затем поиграть с различными настройками и профилями.

Тестовый проект для этой статьи можно скачать с GitHub.
По материалам сайта jayway.
Вольный перевод — Pavel Bobkov

Источник

Android custom view padding

Sometimes, extending a standard Android View is not enough. For many purposes, you will need to actually draw the view yourself to accomplish a task. In this tutorial, we’ll make a view that draws a line chart using the Canvas class and also learn a bit about how the view dimensions and padding works.

By the way, if you haven’t already, you might want to read the previous part as well.

Drawing the first pixels

If you plan to draw your own content in a custom view the best thing is to just extend the base class: View. This is the most basic building block of the UI and is also a fully functional class, though somewhat lacking in features (but that’s for us to implement).

So, we start with creating a new class that extends View. To draw our first pixels, we just need to override the onDraw() method. In the onDraw() method we will get a canvas that we can fill with our pixels. There is no need to call the superclass implementation of onDraw() in this case since for View, onDraw() is actually just an empty method.

Читайте также:  Кингдом раш оригинс для андроид

This code will draw a line with a blue color that starts in (0, 0) and ends at (getWidth(), getHeight()) with a width of 4 pixels. The Paint class is used to control how things are drawn. Although the paint object can do quite a lot of fancy effects, it’s only used here to control what color and style we draw with.

Note that when drawing the content of the View the top left part of the view is at (0, 0) regardless of where the view is on the screen. The View class has methods called getLeft() and getTop() but these return the view’s position relative to its parent view so these should not be used when drawing.

So, now we created our own view that draws a line. Not that useful maybe but it’s a start at least.

Adding padding

When you’ve done XML layouts you have probably used padding on the views. However, if you try using padding for the view we just created you’ll notice that it doesn’t have an effect. That’s because we haven’t taken padding into account yet in our view.

Remember that the way padding works is that the width of the view includes the padding. If the view is 100 pixels wide and the padding on both sides is 10 pixels, then the width available for the actual content is 80 pixels (the same is of course true for the height). So, when we use getWidth() it returns the width including the padding. We can get the padding by using the methods getPaddingTop(), getPaddingBottom, getPaddingLeft() and getPaddingRight().

In order to support padding when drawing our line, the line should start at (getPaddingLeft(), getPaddingTop()) instead and end, not at the lower right corner but the lower right corner minus the padding.

Our refactored onDraw method now looks like this:

Now, changing the padding in the XML file will have the intended effect. The app now looks like this:


Here, I’ve set the background of the view to a dark gray color. As you can see, the background will be drawn outside of the padding but this is normal behavior.

Depending on how you plan to use the custom view, you might not need to support padding. However, I would definitely recommend to make sure your view supports it from the start, even though you think you won’t need it. Adding padding support to a more complex view that for example has many sub-items and includes touch handling can be a hassle. Making sure to support padding from the start is an easy way to future-proof your view.

Drawing the line chart

Now, I said in the beginning that this view was going to draw a line chart. So let’s start working with that. The first step is to have some data to draw.

This lets a user of this view set the data that we should display. For each data point in the graph we really need two values, the x and the y values. But, if we assume that the x values of the data points are equally spaced (which is likely) then we can just use the index as x value. What we get in this method are the y values of the graph.

Now we also need to draw the data points. But we also need to scale them so they’ll fit in the view. To scale the values, it’s convenient to make a helper method like this.

Читайте также:  Плейлисты для vlc android

This method takes a float, a y data point, and the current max value of all points and returns another float, a y position in the view. The first step is to scale the value so that the graph will fill the entire view. Note that to compute the height of the view, we subtract the padding both at the top and at the bottom. Then we need to invert the value. The reason for this is that in the view coordinates, higher y values are further down, but in the graph, higher y values should be higher in the view. Then, finally, we need to offset the y value in order to take padding into account.

Now we’re ready to draw the actual line chart. We could draw the chart by drawing lines between the data points, but we’re going to do it a slightly different way by using a path. Right now the difference will not be noticeable but it will enable us to make it a bit nicer later on. Now the onDraw() method looks like this.

The first part constructs the path using the getYPos() method we created earlier. It also uses a similar getXPos() function that works the same way except it doesn’t need to invert values. The path construction starts with initializing the path at the start position. Then, for each data point, we extend the path with a line from where we are, to the next data point.

The second part is almost the same as before, the only difference being that instead of drawLine() we call drawPath().

The result, with some fake data, looks like this.

It’s starting to look like a line chart. Now it’s time to look at some details as well.

Adding details

The first thing that we will do is to draw the chart with antialiasing turned on. That will reduce the jagged edge look from the chart and make it a lot smoother. Anti aliasing is controlled by the paint object and can be turned on like this

Another thing that will make the line chart to look a bit better is a drop-shadow for the line. Drop shadows are also easy to add, just being another single function call.

Now, everything we draw with the paint will generate a drop shadow as well. The first argument is the blur radius that determines how blurry the shadow will be. The higher number, the more blurrier the shadow. If you set the blur radius to 0, the shadow layer will be removed. The next two arguments is the drop shadow offset. In this case the shadow will be 2 pixels to the right and 2 pixels lower than what we draw. The last argument is the color of the shadow and here we’ve set it to half transparent black.

Here I’ve also added horizontal lines in the background to make it a bit more appealing and to make it look a bit more like chart. There are some logic that determines where to draw the lines and how many but it’s not really important for this tutorial.

From here on we can add quite a lot of things to our line chart view depending on what we want it to look like. With the canvas we can draw lines, paths, rectangles, ovals, bitmaps and so on. With the paint object we can change fill-style, color, stroke-width, effects and lots of other things. I would recommend to take a look at both Canvas and Paint in the Android reference and then playing around a bit with the different settings and shapes.

In the next part we will go through how to animate our new LineChartView.

You can find the sources for this part here.

Источник

Оцените статью