Статьи

Android SDK: рисование с использованием заливки рисунком

В этом руководстве показано, как усовершенствовать приложение для рисования, позволяя пользователю рисовать заливкой рисунком, а не сплошными цветами. Читай дальше!

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

Вот предварительный просмотр приложения для рисования шаблона, которое мы создадим в этом уроке:

Рисование с узорами

Учебник проведет вас через процесс создания отдельного приложения, но также будет включать советы по использованию кода для улучшения приложения, которое мы создали в этой серии. Папка для загрузки исходного кода включает в себя как приложение, которое мы создали в этом руководстве, так и расширенную версию общего приложения для рисования, которое мы создали в этой серии. Вот предварительный просмотр существующего приложения, улучшенного с помощью функции рисования шаблона:

Рисование с узорами

Хотя вы можете завершить этот урок, не проработав серию « Приложение для рисования », мы остановимся на некоторых деталях функций рисования, которые были рассмотрены более подробно. Мы включим полные инструкции по использованию кода в новом приложении, а также укажите, как вы можете использовать его для улучшения существующего приложения для рисования. Если у вас уже есть приложение, которое мы создали в этой серии, вы можете сразу перейти к части 2, шаг 1 руководства.

Если вы запускаете новое приложение для этого учебника, создайте его в Eclipse сейчас, выбрав минимальный уровень API 14 и другие параметры по вашему выбору. Позвольте Eclipse создать пустой Activity и макет для приложения. Мы будем использовать большую часть того же кода, который мы использовали в серии приложений для рисования, поэтому для получения дополнительной информации о функциональности обратитесь к трем учебникам в нем.

Добавьте в приложение новый класс для пользовательского представления, в котором будет происходить рисование, назовите класс «DrawingView» и расширьте объявление открытия следующим образом:

1
public class DrawingView extends View

Вам понадобятся следующие операторы импорта в классе:

01
02
03
04
05
06
07
08
09
10
11
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

Добавьте следующие переменные экземпляра в класс:

01
02
03
04
05
06
07
08
09
10
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF000000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;

Дайте классу метод конструктора, в который мы вызовем вспомогательный метод, который мы добавим далее:

1
2
3
4
public DrawingView(Context context, AttributeSet attrs){
    super(context, attrs);
    setupDrawing();
}

Добавьте вспомогательный метод сейчас:

01
02
03
04
05
06
07
08
09
10
11
private void setupDrawing(){
    drawPath = new Path();
    drawPaint = new Paint();
    drawPaint.setColor(paintColor);
    drawPaint.setAntiAlias(true);
    drawPaint.setStrokeWidth(50);
    drawPaint.setStyle(Paint.Style.STROKE);
    drawPaint.setStrokeJoin(Paint.Join.ROUND);
    drawPaint.setStrokeCap(Paint.Cap.ROUND);
    canvasPaint = new Paint(Paint.DITHER_FLAG);
}

Метод устанавливает класс для рисования. Переопределите метод для случая, когда представлению назначен размер, следующий:

1
2
3
4
5
6
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    drawCanvas = new Canvas(canvasBitmap);
}

Теперь переопределите метод onDraw, чтобы отобразить рисунок, нарисованный пользователем:

1
2
3
4
5
@Override
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
    canvas.drawPath(drawPath, drawPaint);
}

Наконец, добавьте следующий метод для реализации пользовательского рисунка посредством касания в представлении:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
public boolean onTouchEvent(MotionEvent event) {
    float touchX = event.getX();
    float touchY = event.getY();
    //respond to down, move and up events
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        drawPath.moveTo(touchX, touchY);
        break;
    case MotionEvent.ACTION_MOVE:
        drawPath.lineTo(touchX, touchY);
        break;
    case MotionEvent.ACTION_UP:
        drawPath.lineTo(touchX, touchY);
        drawCanvas.drawPath(drawPath, drawPaint);
        drawPath.reset();
        break;
    default:
        return false;
    }
    //redraw
    invalidate();
    return true;
}

Теперь давайте отобразим пользовательский вид в пользовательском интерфейсе приложения. Откройте основной файл макета и включите следующую схему:

1
2
3
4
5
6
7
8
9
<LinearLayout xmlns:android=»http://schemas.android.com/apk/res/android»
    xmlns:tools=»http://schemas.android.com/tools»
    android:layout_width=»match_parent»
    android:layout_height=»match_parent»
    android:background=»#FFCCCCCC»
    android:orientation=»vertical»
    tools:context=».MainActivity» >
 
</LinearLayout>

Внутри Linear Layout добавьте экземпляр пользовательского класса View, который вы создали, используя префикс пакета для вашего собственного приложения:

01
02
03
04
05
06
07
08
09
10
<com.example.patterndraw.DrawingView
    android:id=»@+id/drawing»
    android:layout_width=»fill_parent»
    android:layout_height=»0dp»
    android:layout_marginBottom=»3dp»
    android:layout_marginLeft=»5dp»
    android:layout_marginRight=»5dp»
    android:layout_marginTop=»3dp»
    android:layout_weight=»1″
    android:background=»#FFFFFFFF» />

Мы хотим, чтобы область холста заполняла пространство отдельно от кнопок палитры, которые мы добавим далее.


Мы собираемся использовать 8 шаблонных заливок — вы можете использовать следующие изображения или создать свои собственные, если хотите. Сохраните их в папку (и) drawables вашего проекта — они включены в папку загрузки исходного кода. Мы будем использовать имена файлов для ссылки на изображения в коде приложения.

Шаблон
Шаблон
Шаблон
Шаблон
Шаблон
Шаблон
Шаблон
Шаблон

Вы можете использовать свои собственные изображения шаблонов, если хотите, если они содержат мозаичное растровое изображение. Мы будем использовать изображения на кнопках шаблонов в пользовательском интерфейсе, а также в самих функциях рисования. Мы показываем их на кнопках, чтобы пользователь мог видеть, как выглядит каждый шаблон, прежде чем выбрать один.

Давайте теперь добавим палитру в наш пользовательский интерфейс для кнопок шаблонов. Откройте файл макета. Если вы работаете с приложением, которое мы создали в этой серии, вы можете добавить новые кнопки в область палитры для шаблонов — см. Совет ниже и обратитесь к исходному коду для загрузки завершенного примера существующего приложения с добавленной новой функциональностью. , Для нового приложения добавьте следующее после пользовательского элемента View, который вы добавили:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<LinearLayout
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:layout_gravity=»center»
    android:orientation=»vertical» >
    <!— top row —>
    <LinearLayout
        android:layout_width=»wrap_content»
        android:layout_height=»wrap_content»
        android:orientation=»horizontal» >
    </LinearLayout>
    <!— bottom row —>
    <LinearLayout
        android:layout_width=»wrap_content»
        android:layout_height=»wrap_content»
        android:orientation=»horizontal» >
    </LinearLayout>
</LinearLayout>

Мы перечислим четыре кнопки в каждом ряду. Добавьте первые четыре внутри линейного макета для верхнего ряда:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<ImageButton
    android:layout_width=»30dp»
    android:layout_height=»30dp»
    android:layout_margin=»2dp»
    android:background=»@drawable/pattern1″
    android:contentDescription=»pattern»
    android:onClick=»paintClicked»
    android:src=»@drawable/paint»
    android:tag=»pattern1″ />
<ImageButton
    android:layout_width=»30dp»
    android:layout_height=»30dp»
    android:layout_margin=»2dp»
    android:background=»@drawable/pattern2″
    android:contentDescription=»pattern»
    android:onClick=»paintClicked»
    android:src=»@drawable/paint»
    android:tag=»pattern2″ />
<ImageButton
    android:layout_width=»30dp»
    android:layout_height=»30dp»
    android:layout_margin=»2dp»
    android:background=»@drawable/pattern3″
    android:contentDescription=»pattern»
    android:onClick=»paintClicked»
    android:src=»@drawable/paint»
    android:tag=»pattern3″ />
<ImageButton
    android:layout_width=»30dp»
    android:layout_height=»30dp»
    android:layout_margin=»2dp»
    android:background=»@drawable/pattern4″
    android:contentDescription=»pattern»
    android:onClick=»paintClicked»
    android:src=»@drawable/paint»
    android:tag=»pattern4″ />

Добавьте следующие четыре внутри линейного макета для нижнего ряда:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<ImageButton
    android:layout_width=»30dp»
    android:layout_height=»30dp»
    android:layout_margin=»2dp»
    android:background=»@drawable/pattern5″
    android:contentDescription=»pattern»
    android:onClick=»paintClicked»
    android:src=»@drawable/paint»
    android:tag=»pattern5″ />
<ImageButton
    android:layout_width=»30dp»
    android:layout_height=»30dp»
    android:layout_margin=»2dp»
    android:background=»@drawable/pattern6″
    android:contentDescription=»pattern»
    android:onClick=»paintClicked»
    android:src=»@drawable/paint»
    android:tag=»pattern6″ />
<ImageButton
    android:layout_width=»30dp»
    android:layout_height=»30dp»
    android:layout_margin=»2dp»
    android:background=»@drawable/pattern7″
    android:contentDescription=»pattern»
    android:onClick=»paintClicked»
    android:src=»@drawable/paint»
    android:tag=»pattern7″ />
<ImageButton
    android:layout_width=»30dp»
    android:layout_height=»30dp»
    android:layout_margin=»2dp»
    android:background=»@drawable/pattern8″
    android:contentDescription=»pattern»
    android:onClick=»paintClicked»
    android:src=»@drawable/paint»
    android:tag=»pattern8″ />

Совет: Для приложения, которое мы создали в серии, измените этот код, чтобы использовать те же структуры Image Button, что и у ваших цветных кнопок, но с рисунком, отображаемым как нарисованный вместо цвета, и именем рисунка в качестве атрибута тега, как в коде выше. Вы можете заменить некоторые из своих цветных кнопок шаблонными кнопками или просто добавить некоторые рядом с цветными кнопками. Если вы добавляете много кнопок в приложение, вам может потребоваться уменьшить размеры, чтобы они аккуратно помещались на разных экранах.

Каждая кнопка изображения определяет метод для вызова по щелчкам пользователя — этот метод сможет получить доступ к имени шаблона для нажатой кнопки из атрибута тега.


Совет: Вы можете оставить основной класс Activity таким, какой он есть, если вы завершили серию, единственные изменения, которые вам нужно будет сделать, — это пользовательский класс View, как вы увидите ниже.

Теперь мы можем реализовать с помощью шаблона заливки. В основной класс Activity вашего приложения добавьте следующий импорт:

1
import android.view.View;

Перед методом onCreate добавьте следующую переменную экземпляра для пользовательского класса View:

1
private DrawingView drawView;

В onCreate создайте его экземпляр со ссылкой на пользовательский экземпляр View, который мы добавили в макет:

1
drawView = (DrawingView)findViewById(R.id.drawing);

Затем добавьте метод, который мы перечислили как атрибут onClick для кнопок шаблона:

1
2
3
public void paintClicked(View view){
//set pattern
}

Внутри метода извлеките тег из шаблона Image Button, по которому щелкнули мышью:

1
String pattern = view.getTag().toString();

Нам нужен пользовательский вид, чтобы установить заливку шаблона на основе выбора пользователя. В своем классе «DrawingView» добавьте следующий метод (см. Совет ниже, если вы улучшаете существующее приложение для рисования в качестве альтернативы добавлению этого метода):

1
2
3
public void setPattern(String newPattern){
//set pattern
}

Внутри метода сначала аннулируйте View:

1
invalidate();

Мы будем использовать имя рисованного шаблона, чтобы ввести его в класс рисования в качестве растрового изображения. Получить ссылку на идентификатор ресурса для переданного шаблона String:

1
int patternID = getResources().getIdentifier(newPattern, «drawable», «com.example.patterndraw»);

Измените название пакета в соответствии со своим собственным. Далее в методе декодируйте ресурс как растровое изображение, передавая полученное значение идентификатора:

1
Bitmap patternBMP = BitmapFactory.decodeResource(getResources(), patternID);

Вместо того, чтобы рисовать непосредственно с помощью растрового изображения, мы будем рисовать сплошным цветом и использовать растровое изображение в качестве шейдера для него. Создайте объект Shader, используя раскодированный рисунок Bitmap:

1
2
BitmapShader patternBMPshader = new BitmapShader(patternBMP,
    Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

Мы хотим, чтобы рисунок повторялся по всей области, на которой он нарисован. Установите цвет на сплошной белый и используйте шейдер для шаблона:

1
2
drawPaint.setColor(0xFFFFFFFF);
drawPaint.setShader(patternBMPshader);

Это создаст впечатление, что пользователь рисует с рисунком в виде краски, как и сплошным цветом. Неважно, какого размера будет рисунок для рисования по шаблону, поскольку его можно будет непрерывно повторять по всему холсту, где бы пользователь ни захотел рисовать.

Вернувшись в основной метод ActivityClickCeded, теперь вы можете вызывать новый метод с шаблоном String, полученным из тега кнопки:

1
drawView.setPattern(pattern);

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

Совет: Если вы улучшаете существующее приложение для рисования, вы можете продолжить использовать метод setColor из основного занятия, изменив содержимое метода в классе DrawingView, чтобы использовать описанную выше обработку, если переданная цветная строка не начинается с Символ «#», используя существующую обработку, если это так. Если пользователь выбрал цвет, а не узор, вам также нужно установить шейдер в объекте Paint обратно на ноль — подробности см. В исходном коде.

Теперь вы сможете запустить приложение и протестировать функциональность рисования рисунков. Выбор рисунка путем нажатия кнопок палитры, затем касания области холста пальцем и перетаскивания по экрану будет рисовать с выбранным рисунком, как и сплошным цветом.


В этом уроке мы продемонстрировали, как реализовать функции рисования, используя шаблоны, а не цвета в ваших приложениях для Android. Использование заливки узором лишь немного отличается от использования сплошного цвета, но, как вы уже видели, требует немного больше обработки. Не забудьте проверить загрузку исходного кода для получения дополнительной информации, если вы работали над приложением, которое мы создали в серии приложений для рисования. Существует множество других опций, которые вы можете изучить в приложениях для рисования, включая прозрачность, о которых мы расскажем в следующем уроке. Мы также рассмотрим взаимодействие, которое происходит не с сенсорного экрана. А пока посмотрите, сможете ли вы улучшить свои приложения для рисования другими способами.