Графика
Пакет android.graphics имеет все необходимые библиотеки для работы с двухмерной графикой. Существует несколько подходов для рисования графики.
Для рисования простой графики, которая не будет динамически изменяться во время работы приложения, обычно используют класс, наследующий от View и задействуют метод onDraw().
В метод передаётся объект Canvas, у которого есть различные графические методы.
Стандартная реализация подобного подхода выглядит следующим образом:
В методе setContentView() вместо ссылки на разметку передаётся класс MyView, наследующий от View:
В методе onDraw() можете рисовать:
Для рисования динамической графики больше подойдёт класс SurfaceView, имеющий дополнительные возможности. Данному классу мы посвятим отдельный материал.
Класс Color
Класс Color отвечает за цвета. Цвета можно описывать четырьмя числами в формате ARGB, по одному для каждого канала(Alpha, Red, Green, Blue).
Класс Paint
Класс Paint содержит стили, цвета и другую графическую информацию для рисования графических объектов. Он позволяет выбирать способ отображения графических примитивов, которые вы рисуете на объекте Canvas с помощью методов. Изменяя объект Paint, можно контролировать цвет, стиль, шрифт и специальные эффекты, используемые при рисовании. Например, чтобы установить сплошной цвет для рисования линии, нужно вызвать метод Paint.setColor().
В этом примере мы использовали готовую константу. Также можно указать 32-битное целое число, закодированное в схеме ARGB8888.
Можно установить цвет через его составляющие:
Стиль объекта Paint, задаваемый с помощью метода setStyle(), позволяет рисовать либо очертания графического примитива (STROKE), либо его заливку (FILL), либо и то, и другое сразу (STROKE_AND_FILL).
Помимо этих простых методов класс Paint поддерживает прозрачность и может быть изменён с помощью различных шейдеров, фильтров и эффектов, которые предоставляют богатый набор сложных красок и кистей.
Использование полупрозрачности
Любой цвет в Android содержит свойство прозрачности (альфа-канал). Указать его можно при создании описывающей цвет переменной, используя методы argb() и parseColor():
Но мы можем задать прозрачность уже существующего объекта Paint с помощью метода setAlpha():
Пример использования метода setAlpha() для наложения двух картинок.
Режим Xfermode
Изменение режима Xfermode для объекта Paint влияет на способ наложения новых цветов поверх уже нарисованных. В обычных обстоятельствах при рисовании поверх имеющегося рисунка создастся новый верхний слой. Если новый объект Paint на 100% непрозрачный, он полностью закрасит все, что находится под областью для рисования; если он полупрозрачный, то только затенит лежащие ниже цвета. Подклассы Xfermode позволяют изменить такое поведение.
- AvoidXfermode. Определяет цвет, поверх которого объект Paint не может (или наоборот — может только поверх него) рисовать. Задается также параметр tolerance, указывающий на допустимое отклонение.
- PixelXorXfermode. Применяет простое побитовое исключение (XOR) при рисовании поверх существующих цветов.
- PorterDuffXfermode. Мощный режим, с помощью которого можно использовать любое из шестнадцати правил смешивания изображений Портера-Даффа, управляя процессом наложения кисти на уже существующий рисунок.
Для того чтобы применить один из этих режимов, используйте метод setXferMode():
Сглаживание
При создании нового объекта Paint вы можете передать в его конструктор несколько флагов, которые будут влиять на способ отображения. Одним из наиболее интересных из них считается флаг ANTI_ALIAS_FLAG, обеспечивающий сглаживание диагональных линий, рисуемых объектом Paint (снижая при этом производительность).
Сглаживание играет важную роль в процессе отрисовки текста, значительно упрощает его восприятие. Чтобы сделать текст более гладким, можете использовать флаг SUBPIXEL_TEXT_FLAG, который применяет субпиксельное сглаживание. Можно задать оба этих флага программно, используя методы setSubpixelText() и setAntiAlias():
Класс Path
Класс Path позволяет рисовать контуры разных типов — пунктиры, сглаживание линий и т.д.
Класс Canvas
Класс Canvas представляет собой специальную поверхность (холст), на которой вы можете рисовать. С помощью многочисленных методов класса вы можете рисовать линии, окружности, дуги и так далее.
Класс Bitmap
Класс Bitmap отвечает за растровые картинки.
Источник
Основы работы с 2D графикой на Android
Здравствуйте, читатели Хабра!
Совсем недавно я начал изучать программирование под android и конечно сразу поставил перед собой интересную цель — сделать небольшую игру.
Ознакомившись за пару дней с Java (отличный курс: intuit.ru/department/pl/javapl/) и почитав developer.android.com, перешел к самому главному пункту — к графике. И теперь предлагаю вам разобрать работу с ней на простом примере.
Теория
Для вывода 2D графики android предоставляет два пути:
а) Выводить графику в объекте View, который находится в вашем layout.
В этом случае вся графика/анимация управляется самим андроидом и вы, грубо говоря, только определяете какую картинку показать.
Этот способ подходит, если вы хотите вывести простую статичную графику, которая не должна динамично изменяться.
б) Рисовать графику напрямую на канве (Canvas). В этом случае вы вручную вызываете методы канвы для рисования картинок, геометрических объектов и текста.
Вы должны использовать этот способ, если графика в вашей программе должна часто обновляться/перерисовываться. Это как раз то, что нам нужно для игры.
Вариант «б» можно реализовать двумя способами:
1) В том же Activity, в котором находится наш класс View для вывода графики, мы зызываем метод invalidate(), который обновляет содержимое канвы.
2) Создаем отдельный поток, который обновляет содержимое канвы настолько быстро, насколько может (в этом случае не нужно вызывать invalidate()).
В первом случае изображение будет обновляться только по нашему требованию, что подходит для простых игр типа шахмат, которые не требует большого fps. Его мы и будем использовать в примере.
Сначала импортируем нужные пакеты.
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.MotionEvent;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
В нашем Activity создадим класс GraphicsView, расширяющий View и определим внутри него метод onDraw(), в котором будут находиться команды рисования.
public class Game extends Activity
<
@Override
public void onCreate(Bundle savedInstanceState)
<
super.onCreate(savedInstanceState);
GraphicsView myview=new GraphicsView(this); // создаем объект myview класса GraphicsView
setContentView(myview); // отображаем его в Activity
>
public class GraphicsView extends View
<
public GraphicsView(Context context)
@Override
protected void onDraw(Canvas canvas)
<
// здесь будут находиться код, рисующий нашу графику
>
Для примера будем выводить картинку, а именно, стандартную иконку приложения.
protected void onDraw(Canvas canvas)
<
// загружаем иконку из ресурсов в объект myBitmap
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
// рисуем myBitmap на канве в координатах 10, 10
canvas.drawBitmap(myBitmap, 10, 10, null);
>
Можете запустить программу и вы увидите следующее:
Каждый раз, когда нам необходимо обновить содержимое GraphicsView (например при изменении координат выводимой картинки), мы должны вызвать invalidate(), который говорит андроиду, что мы хотели бы перерисовать содержимое GraphicsView, и он вызовет наш метод onDraw(). Давайте будем вызывать его при касании экрана.
Определим у нашего класса GraphicsView метод onTouchEvent().
public boolean onTouchEvent(MotionEvent event)
<
if(event.getAction() == MotionEvent.ACTION_DOWN) < invalidate() >
return true;
>
Теперь, запустив программу и коснувшись экрана, мы будем вызывать invalidate(). Но, так как код внутри onDraw() у нас не меняется, то и никаких изменений на экране мы не увидим.
Давайте менять координаты картинки на те, в которых произошло прикосновение.
Дополним код командами event.getX() и event.getX(). При прикосновении к экрану они получат координаты касания. Сохраним их в переменных touchX и touchY.
public boolean onTouchEvent(MotionEvent event)
<
if(event.getAction() == MotionEvent.ACTION_DOWN)
<
touchX = event.getX();
touchY = event.getY();
invalidate();
>
return true;
>
Вернемся к onDraw. Зададим переменные типа float с начальными нулевыми значениями и затем впишем их вместо фиксированных координат рисунка.
float touchX = 0;
float touchY = 0;
@Override
protected void onDraw(Canvas canvas)
<
// загружаем иконку из ресурсов в объект myBitmap
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
// рисуем myBitmap на канве в координатах касания
canvas.drawBitmap(myBitmap, touchX, touchY, null);
>
Можете запустить программу и коснуться экрана — картинка переместится в точку касания.
Надеюсь, что этот пример послужит вам толчком для дальнейшего изучения программирования для Android и возможно создания вашей первой игры.
Источник
Pretty Painter – мое первое приложение под Android
Всем привет! Хотелось бы поделиться с вами своим опытом создания первого приложения под Android. И если вы уже давно присматриваетесь к этой платформе, но все еще почему-то не решаетесь начать разрабатывать свои приложения, то, я надеюсь, мой топик подтолкнет вас к этому. Под катом пять причин почему не нужно сомневаться и пора действовать и еще несколько интересных моментов.
Исходные данные
Веб-разработчик в творческом отпуске. Знания:
- HTML/CSS — выше среднего
- JS — средние
- PHP — выше среднего
+ совсем небольшие познания в C#. Где же Java спросит читатель? Знаниями сего языка до разработки похвастаться увы не мог. И вот вам первая причина для того, чтобы приступить к разработке сейчас — «Не обязательно читать толстый мануал по Java».
Книга: «Google Android. Программирование для мобильных устройств». Обязательно? Нет, если вы дружите с английским, достаточно документации на сайте. Если же все таки с английским все плохо, как, например у меня, мой вам совет, не читайте книжку от корки до корки, отобьете все желание. Пользуйтесь как справочным материалом — в этом плане она очень полезна. Причина вторая: «Не обязательно покупать книгу если вы хорошо владеете английским языком».
Устройство: HTC Desire Z. А что без него никак? Я тоже так думал, поэтому поднакопил деньжат и все же купил, но в итоге мое приложение запустилось и на эмуляторе и итоговый результат был таким же как на смартфоне. Поэтому наличие устройства не критично, но если есть возможность, то лучше его приобрести. Причина третья: «Не обязательно покупать смартфон».
Целью завоевать планету не задавался, извините. Я хотел сделать простенький графический редактор аля Paint и понять как устроены андроид-приложения изнутри. Какими-то сроками не задавался, но забегая вперед скажу, что на реализацию вместе с изучением ушло чуть более недели.
Процесс
Процесс установки и настройки рабочего места описывать не буду, благо этот вопрос и его решение были озвучены уже не раз. Для создания редактора, мне нужно было понять как работают в Android с графикой. И первое что пришло на ум — это игры. Ведь там идет постоянная работа с графикой, что я и принялся изучать.
Первым же запросом к гуглу я наткнулся на такой вот простенький шаблон игры. Распаковав архив я принялся изучать исходник. Смотря на причудливые super вместо parent, объявления классов в классе и переопределения методов при создании объектов невольно думаешь, а не повернуть ли назад? Но мы так просто не сдаемся.
Разобравшись, что к чему, я создал каркас приложения на основе этого шаблона и начал творить. Довольно быстро я нашел статью про взаимодействие с сенсорным экраном и как ребенок радовался как под пальцами появляются круги. Тыкал в экран около часа, не меньше. Дальше, не долго думая, я убрал очистку экрана и оставил только рендер, предполагая, что теперь экран не будет очищаться и соответственно все, что пользователь будет рисовать, будет добавляться к уже нарисованному. В принципе так оно и было, но происходило это как-то странно. При долгом нажатии круги получались плотными, а вот при легком касании оставленная окружность мерцала. Как я понял, проблема была связана с сменой экранных буферов и такой топорный подход, как мой, тут не пройдет. Нужно было что-то другое.
Решение было найдено в очень вовремя в попавшихся на глаза исходниках Sketcher. Оно заключалось в рисовании на поверхности основанной на изображении и последующей передачи ее на рабочую поверхность. Это приложение было просто золотой находкой, за что автору (WarGoth) огромное спасибо! В последствии я работал опираясь на него. А также без изменения использовал диалог выбора цвета. И вот вам и четвертая причина: «В сети очень много исходников готовых андроид-приложений и без пищи для ума вы не останетесь».
В принципе пол-дела было сделано — приложение уже умело рисовать, осталось сделать интерфейс, меню и сформировать работу с пользователем, чем я и занимался последующие четыре дня. Описывать весь процесс думаю смысла нет, про все это действительно очень много информации. Далеко ходить не нужно, почти все необходимые знания я получил тут, на Хабре. В процессе работы возникали вопросы на которые я почти всегда находил ответы на stackoverflow. И это пятая причина для того, чтобы не откладывать изучение платформы в долгий ящик «Почти на все вопросы возникающие во время разработки можно найти ответы».
Вот в принципе и все и я наверное прослыву Капитаном. Но так и есть, и все чаще авторы новых статей рассказывают уже очевидные вещи, а это значит что информации для старта уже достаточно. Поэтому, хватит раздумывать — пора действовать! Конечно если сообществу будут интересны какие-то конкретные моменты по приложению я могу их описать в отдельной статье, но пока причин для этого не вижу.
От появления идеи до создания приложения прошло 8 дней, еще два дня я подготавливал приложение к запуску. За это время я узнал, много нового о платформе, языке и тонкостях работы приложений и у меня появилось желание написать, что нибудь еще. Конечно, мне здорово помогли мои познания в верстке и программировании, но мне кажется главное тут, как и в любом деле, не знания, а желание.
Ну и напоследок советы, которые помогут избежать головной боли:
- Не стоит хранить важные переменные в потоках, они умирают при первой возможности. Наверное я бы про это знал если бы прочитал тот самый мануал по Java. Решением стало перенос переменных в класс вида
- Если вы хотите, чтобы ваше приложение реагировало на поворот экрана, подумайте об этом заранее, так как при повороте приложение полностью перезапускается, решите как вы будете сохранять состояние
- При программном изменении выбранного значения в элементе комбобоксе (Spinner) вызывается событие onOptionsItemSelected и непонятно откуда оно приходит, от пользователя или от приложения. Решением стало расширение класса Spinner и переопределение метода OnClick, которое вызывается при выборе пункта пользователем
- Используйте стили для разметки, это может здорово помочь при изменении интерфейса или, например, при локализации, если надписи не будут умещаться на экране
- Используйте ресурсы для хранения строковых переменных. Тогда локализация не доставит никаких проблем
- Используйте системные ресурсы Android, дабы не плодить иконки, тексты и прочее. Я часто встречал копии системных иконок в исходниках. Ресурсы доступны через android.R в коде и android/ в разметке
- При использовании анимации, прячьте объекты требующие активной перерисовки, такие как Surface, иначе анимация будет безбожно тормозить
Теперь о самом приложении. Это обычная «рисовалка» с возможностью настраивать кисти, сохранять полученный результат и делиться им с друзьями. Оно не претендует на гениальность, но как мне кажется не лишено права быть выложенным на маркет. Прошу не судить строго, как никак первенец.
А теперь, приятный, я надеюсь, сюрприз. Исходный код приложения открыт. Он не идеален и плохо комментирован, но со временем я все это исправлю. Пользуйтесь на здоровье!
Источник