Android SDK: создание приложения для рисования - сенсорное взаимодействие
() translation by (you can also view the original English article)
В серии нескольких статье мы создадим приложение для рисования с помощью пальцев для Android, использующее сенсорное взаимодействие. У пользователя будет возможность выбирать цвет из цветовой палитры, размер кисти, стирать, создавать новый рисунок или сохранять уже существующий в галерее устройства.
Формат урока
Данный урок по созданию приложения для рисования будет состоять из трех частей:
Просмотр конечного результата



В первой части серии нескольких уроков мы создадим пользовательский интерфейс. Во второй части мы осуществим рисование на холсте и выбор цветов. В заключительной части мы представим возможность стирать, создавать новые рисунки и сохранять их в галерее пользовательского устройства. Мы рассмотрим опции, которые вы сможете использовать для улучшения этого приложения, проходя в будущем другие учебные материалы, включая заливку холста, прозрачность и другое взаимодействие, отличное от сенсорного.
1. Подготовка к рисованию
Шаг 1
В прошлый раз мы создали класс с именем «DrawingView», который представляет собой пользовательский View для функций рисования, которые должны выполняться внутри. Мы создали схему объявления класса и метод с именем «setupDrawing» - вот сейчас мы сделаем это. В своем классе DrawingView
добавьте следующие операторы импорта:
1 |
import android.graphics.Bitmap; |
2 |
import android.graphics.Canvas; |
3 |
import android.graphics.Paint; |
4 |
import android.graphics.Path; |
5 |
import android.view.MotionEvent; |
Затем добавьте некоторые переменные экземпляра в верхней части класса:
1 |
//drawing path
|
2 |
private Path drawPath; |
3 |
//drawing and canvas paint
|
4 |
private Paint drawPaint, canvasPaint; |
5 |
//initial color
|
6 |
private int paintColor = 0xFF660000; |
7 |
//canvas
|
8 |
private Canvas drawCanvas; |
9 |
//canvas bitmap
|
10 |
private Bitmap canvasBitmap; |
Когда пользователь прикасается к экрану и перемещает палец, чтоб рисовать, мы будем использовать Path для отслеживания его действий рисования на холсте. Как холст, так и рисунок поверх него представлены объектами Paint. Начальный цвет краски соответствует первому цвету в палитре, которую мы создали в последний раз, и которая будет первоначально выбрана при запуске приложения. Наконец, мы объявляем переменные для холста и растрового изображения: пути пользователя, нарисованные с помощью drawPaint
, будут нарисованы на холсте, который нарисован canvasPaint
.
Шаг 2
Давайте создадим в методе setupDrawing
некоторые из этих переменных, чтобы установить класс для рисования. Сначала создайте объекты рисования Path и Paint:
1 |
drawPath = new Path(); |
2 |
drawPaint = new Paint(); |
Затем установите начальный цвет:
1 |
drawPaint.setColor(paintColor); |
Теперь задайте начальные свойства пути:
1 |
drawPaint.setAntiAlias(true); |
2 |
drawPaint.setStrokeWidth(20); |
3 |
drawPaint.setStyle(Paint.Style.STROKE); |
4 |
drawPaint.setStrokeJoin(Paint.Join.ROUND); |
5 |
drawPaint.setStrokeCap(Paint.Cap.ROUND); |
Мы изменим часть этого кода в следующем уроке, когда реализуем возможность выбора размеров кистей; пока мы установим произвольный размер кисти. Настройка сглаживания, штрихов и стилей сделает рисунки пользователя более гладкими.
Завершите метод setupDrawing
, создав экземпляр объекта Paint:
1 |
canvasPaint = new Paint(Paint.DITHER_FLAG); |
На этот раз мы устанавливаем сглаживание, передавая параметр конструктору.
Шаг 3
Нам нужно переопределить несколько методов, чтобы сделать пользовательскую функцию View в виде чертежа. Во-первых, все еще находясь внутри класса DrawingView
, переопределите метод onSizeChanged
, который будет вызываться, когда пользовательскому View присваивается размер:
1 |
@Override
|
2 |
protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
3 |
//view given size
|
4 |
}
|
Внутри этого метода вызовите сначала метод суперкласса:
1 |
super.onSizeChanged(w, h, oldw, oldh); |
Теперь создайте холст для рисования и растрового изображения, используя значения ширины и высоты:
1 |
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); |
2 |
drawCanvas = new Canvas(canvasBitmap); |
Шаг 4
Чтобы позволить классу функционировать как View чертежа пользователя, нам также необходимо переопределить метод onDraw
, поэтому сейчас добавьте его в класс:
1 |
@Override
|
2 |
protected void onDraw(Canvas canvas) { |
3 |
//draw view
|
4 |
}
|
Внутри метода нарисуйте холст и путь рисования:
1 |
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); |
2 |
canvas.drawPath(drawPath, drawPaint); |
Пока мы еще не реализовали возможность для пользователя рисовать путь с помощью Paint, но как только мы это сделаем, он будет представлен в View. Каждый раз, когда пользователь рисует с помощью сенсорного взаимодействия, мы аннулируем View, заставляя выполняться метод onDraw
.
2. Содействие рисованию
Шаг 1
Когда чертеж View находится на экране приложения, мы хотим, чтобы пользователь касался его для регистрации в качестве операций рисования. Для этого нам нужно проследить сенсорные события. В своем классе drawingView
добавьте следующий метод:
1 |
@Override
|
2 |
public boolean onTouchEvent(MotionEvent event) { |
3 |
//detect user touch
|
4 |
}
|
Внутри метода извлеките X и Y позиции касания пользователя:
1 |
float touchX = event.getX(); |
2 |
float touchY = event.getY(); |
Шаг 2
Параметр MotionEvent
в onTouchEvent
методе позволит нам реагировать на определенные события прикосновения. Действия, в которых мы заинтересованы, чтобы применить рисование, - down
, move
и up
. Добавьте оператор switch в метод для ответа на каждый из следующих:
1 |
switch (event.getAction()) { |
2 |
case MotionEvent.ACTION_DOWN: |
3 |
drawPath.moveTo(touchX, touchY); |
4 |
break; |
5 |
case MotionEvent.ACTION_MOVE: |
6 |
drawPath.lineTo(touchX, touchY); |
7 |
break; |
8 |
case MotionEvent.ACTION_UP: |
9 |
drawCanvas.drawPath(drawPath, drawPaint); |
10 |
drawPath.reset(); |
11 |
break; |
12 |
default: |
13 |
return false; |
14 |
}
|
Найдите минутку, чтобы просмотреть этот код. Когда пользователь касается View, мы перемещаемся в это положение, чтобы начать рисовать. Когда он двигает пальцем по View, мы рисуем путь вместе с его прикосновением. Когда он забирает свой палец от View, мы рисуем Path, и перезагружаем его для следующей операции рисования.
Шаг 3
После оператора switch завершите метод, сделав недействительным View и вернув истинное значение:
1 |
invalidate(); |
2 |
return true; |
Вызов invalidate
вызовет выполнение метода onDraw
.
3. Выбор цветов
Шаг 1
Теперь давайте реализуем возможность пользователя выбирать цвета из палитры. В главном Activity приложения добавьте следующие импорты:
1 |
import android.view.View; |
2 |
import android.widget.ImageButton; |
3 |
import android.widget.LinearLayout; |
Добавьте в класс следующую переменную экземпляра:
1 |
private DrawingView drawView; |
Это представляет экземпляр пользовательского View, который мы добавили в макет. Внутри onCreate
, после существующего кода, создайте эту переменную, извлекая ссылку на нее из макета:
1 |
drawView = (DrawingView)findViewById(R.id.drawing); |
Теперь у нас есть View, который отображается в Activity, на котором мы можем вызвать методы в классе DrawingView
.
Шаг 2
Мы устанавливаем исходный цвет в классе чертежа View, давайте теперь настроим пользовательский интерфейс, чтобы отображать и управлять им. В основном классе Activity добавьте другую переменную экземпляра, чтобы отобразить кнопку цвета на палитре:
1 |
private ImageButton currPaint; |
Внутри onCreate
мы теперь хотим получить первую кнопку цвета краски в области палитры, которая изначально будет выбрана. Сначала найдите Linear Layout, содержащуюся внутри:
1 |
LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors); |
Получите первую кнопку и сохраните ее как переменную экземпляра:
1 |
currPaint = (ImageButton)paintLayout.getChildAt(0); |
На кнопке мы будем использовать другое изображение, которое можно нарисовать, чтобы показать, что оно выбрано в настоящий момент:
1 |
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed)); |
Добавьте этот файл в чертежи вашего приложения, указав ему имя "paint_pressed.xml" и введя следующую форму:
1 |
<layer-list xmlns:android="https://schemas.android.com/apk/res/android" > |
2 |
<item>
|
3 |
<shape android:shape="rectangle" > |
4 |
<stroke
|
5 |
android:width="4dp" |
6 |
android:color="#FF333333" /> |
7 |
|
8 |
<solid android:color="#00000000" /> |
9 |
|
10 |
<padding
|
11 |
android:bottom="0dp" |
12 |
android:left="0dp" |
13 |
android:right="0dp" |
14 |
android:top="0dp" /> |
15 |
</shape>
|
16 |
</item>
|
17 |
<item>
|
18 |
<shape xmlns:android="http://schemas.android.com/apk/res/android" > |
19 |
<stroke
|
20 |
android:width="4dp" |
21 |
android:color="#FF333333" /> |
22 |
|
23 |
<solid android:color="#00000000" /> |
24 |
|
25 |
<corners android:radius="10dp" /> |
26 |
</shape>
|
27 |
</item>
|
28 |
</layer-list>
|
Это очень похоже на «paint.xml», который мы создали в последний раз, но с темным цветом вокруг краски.
Шаг 3
Теперь мы можем позволить пользователю выбирать цвета. Когда в последний раз мы создавали макет, мы указали атрибут onClick
для кнопок цветовой палитры; теперь добавьте метод в свой основной класс Activity:
1 |
public void paintClicked(View view){ |
2 |
//use chosen color
|
3 |
}
|
Внутри этого метода сначала убедитесь, что пользователь щелкнул цвет краски, который не выбран в данный момент:
1 |
if(view!=currPaint){ |
2 |
//update color
|
3 |
}
|
Внутри блока if
найдите тег, который мы установили для каждой кнопки в макете, представляя выбранный цвет:
1 |
ImageButton imgView = (ImageButton)view; |
2 |
String color = view.getTag().toString(); |
Для установки цвета нам нужно использовать собственный класс View. Перейдите в класс DrawingView
и добавьте следующий метод:
1 |
public void setColor(String newColor){ |
2 |
//set color
|
3 |
}
|
Внутри метода начните с аннулирования View:
1 |
invalidate(); |
Затем выполните анализ и установите цвет для рисования:
1 |
paintColor = Color.parseColor(newColor); |
2 |
drawPaint.setColor(paintColor); |
Вернемся к нашему основному Activity и в методе paintClicked
, после получения тега цвета, вызовите новый метод на пользовательский чертежный объект View:
1 |
drawView.setColor(color); |
Теперь обновите пользовательский интерфейс, чтобы отобразить новую выбранную краску, и установите предыдущую версию в обычном режиме:
1 |
imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed)); |
2 |
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint)); |
3 |
currPaint=(ImageButton)view; |
Вывод
Теперь вы можете запустить приложение и рисовать на холсте, выбрав цвета для рисования. Вы видите, что кнопки цветовой палитры соответствуют выбранному цвету в данный момент. В этом уроке мы проработали основные функции любого приложения для рисования под Android, поэтому теперь у вас должны быть основные навыки для реализации собственных функций рисования в других приложениях. В заключительной части серии этих уроков мы реализуем стирание, выбор размера кисти и ластика, сохранение рисунков и начало рисования новых.