Автор: Пэн Вейцзя
Бингдун нельзя купить, золотой Бингдун не по карману, вязать Бингдун из шерсти не умею, из пластилина не вылепить, из снега не слепить, но мы научимся рисовать Бингдуна с помощью программы.
Дать рыбу лучше, чем дать удочку. Сегодня мы пошагово научимся рисовать Бингдуна!
Хороший инструмент необходим для хорошей работы. Независимо от того, рисуем ли мы Бингдуна, самолеты, танки или пушки, нужна хорошая координатная система.
Проблема вычисления центральной точки. Здесь важно, чтобы центральная линия и вспомогательные линии были выровнены для обеспечения эстетики.
@Override
public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
int componentWidth = EstimateSpec.getSize(widthEstimateConfig);
int componentHeight = EstimateSpec.getSize(heightEstimateConfig);
this.width = componentWidth;
this.height = componentHeight;
centerX = this.width / 2;
centerY = this.height / 2;
// Убедиться, что вспомогательные линии целые числа
centerX = ((int) (centerX / 50)) * 50;
centerY = ((int) (centerY / 50)) * 50;
Logger.d("width:" + width);
Logger.d("height:" + height);
Logger.d("centerX:" + centerX);
Logger.d("centerY:" + centerY);
recordBg(); // Инициализация координатной системы и сетки
setEstimatedSize(
EstimateSpec.getChildSizeWithMode(componentWidth, componentWidth, EstimateSpec.PRECISE),
EstimateSpec.getChildSizeWithMode(componentHeight, componentHeight, EstimateSpec.PRECISE)
);
return true;
}
```Инициализация координатной системы
```java
private Point mCoo; // Координатная система
private Picture mPicture; // Координатная система и сетка
/**
* Инициализация координатной системы и сетки
*/
private void recordBg() {
// Подготовка размеров экрана
Point winSize = new Point(width, height);
mCoo = new Point(centerX, centerY);
Paint gridPaint = new Paint();
mPicture = new Picture();
Canvas recordCanvas = mPicture.beginRecording(winSize.getPointXToInt(), winSize.getPointYToInt());
// Рисование сетки
HelpDraw2.drawGrid(recordCanvas, winSize, gridPaint);
// Рисование координатной системы
HelpDraw2.drawCoo(recordCanvas, mCoo, winSize, gridPaint);
mPicture.endRecording();
}
Метод onDraw
рисует координатную систему
canvas.drawPicture(mPicture);
Класс-помощник для рисования
/**
* Помощник для рисования
*
* @since 2022-02-09
*/
public class HelpDraw2 {
/**
* Рисование сетки
*/
public static void drawGrid(Canvas recordCanvas, Point winSize, Paint paint) {
// Инициализация рисовального стиля для сетки
paint.setStrokeWidth(2);
paint.setColor(Color.GRAY);
paint.setStyle(Paint.Style.STROKE);
// Установка пунктирного стиля new float[]{видимая длина, невидимая длина}, смещение
paint.setPathEffect(new PathEffect(new float[]{10, 5}, 0));
recordCanvas.drawPath(HelpPath.gridPath(50, winSize), paint);
}
}
``` /**
* Рисование координатной системы
* @param recording Канвас
* @param coo Оригинал координатной системы
* @param winSize Размер экрана
* @param paint Рисовальный стиль
*/
public static void drawCoo(Canvas recording, Point coo, Point winSize, Paint paint) {
// Инициализация рисовального стиля для сетки
paint.setStrokeWidth(4);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
// Установка пунктирного стиля new float[]{видимая длина, невидимая длина}, смещение
paint.setPathEffect(null);
}```java
// Рисование прямых линий
recording.drawPath(HelpPath.cooPath(coo, winSize), paint);
// Левый стрелочный символ
recording.drawLine(winSize.getPointX(), coo.getPointY(), winSize.getPointX() - 40, coo.getPointY() - 20, paint);
recording.drawLine(winSize.getPointX(), coo.getPointY(), winSize.getPointX() - 40, coo.getPointY() + 20, paint);
// Нижний стрелочный символ
recording.drawLine(coo.getPointX(), winSize.getPointY(), coo.getPointX() - 20, winSize.getPointY() - 40, paint);
recording.drawLine(coo.getPointX(), winSize.getPointY(), coo.getPointX() + 20, winSize.getPointY() - 40, paint);
// Рисование текста для координатной системы
drawText4Coo(recording, coo, winSize, paint);
}
}
```java
/**
* Отрисовка текста для координатной системы
*
* @param canvas холст
* @param coo начальная точка координатной системы
* @param winSize размер экрана
* @param paint кисть
*/
private static void drawText4Coo(Canvas canvas, Point coo, Point winSize, Paint paint) {
// Отрисовка текста
paint.setTextSize(50);
canvas.drawText("x", winSize.getPointX() - 60, coo.getPointY() - 40, paint);
canvas.drawText("y", coo.getPointX() - 40, winSize.getPointY() - 60, paint);
paint.setTextSize(25);
// Текст для положительной оси X
for (int i = 1; i < (winSize.getPointX() - coo.getPointX()) / 50; i++) {
paint.setStrokeWidth(2);
canvas.drawText(100 * i + "", coo.getPointX() - 20 + 100 * i, coo.getPointY() + 40, paint);
paint.setStrokeWidth(5);
canvas.drawLine(coo.getPointX() + 100 * i, coo.getPointY(), coo.getPointX() + 100 * i, coo.getPointY() - 10, paint);
}
// Текст для отрицательной оси X
for (int i = 1; i < coo.getPointX() / 50; i++) {
paint.setStrokeWidth(2);
canvas.drawText(-100 * i + "", coo.getPointX() - 20 - 100 * i, coo.getPointY() + 40, paint);
paint.setStrokeWidth(5);
canvas.drawLine(coo.getPointX() - 100 * i, coo.getPointY(), coo.getPointX() - 100 * i, coo.getPointY() - 10, paint);
}
}
``` <!--Y положительной оси текст-->
for (int i = 1; i < (winSize.getPointY() - coo.getPointY()) / 50; i++) {
paint.setStrokeWidth(2);
canvas.drawText(paint, 100 * i + "", coo.getPointX() + 20, coo.getPointY() + 10 + 100 * i);
paint.setStrokeWidth(5);
canvas.drawLine(coo.getPointX(), coo.getPointY() + 100 * i, coo.getPointX() + 10, coo.getPointY() + 100 * i, paint);
}
<!--Y отрицательной оси текст-->
for (int i = 1; i < coo.getPointY() / 50; i++) {
paint.setStrokeWidth(2);
canvas.drawText(paint, -100 * i + "", coo.getPointX() + 20, coo.getPointY() + 10 - 100 * i);
paint.setStrokeWidth(5);
canvas.drawLine(coo.getPointX(), coo.getPointY() - 100 * i, coo.getPointX() + 10, coo.getPointY() - 100 * i, paint);
}
}
}
Выберем понравившуюся картинку Бэддока в качестве фона, настроим прозрачность кисти на 50%;
Подготовка кисти
mPixelMapPaint = new Paint();
mPixelMapPaint.setAlpha(0.5f);
Метод отрисовки изображения
private void drawPixelMap(Canvas canvas) {
Optional<PixelMap> image = PixelMapUtil.getPixelMapFromResource(getContext(), ResourceTable.Media_bdd);
if (image.isPresent()) {
PixelMap pixelMap = image.get();
int pw = pixelMap.getImageInfo().size.width;
int ph = pixelMap.getImageInfo().size.height;
int offX = centerX - pw / 2;
int offY = centerY - ph / 2;
Logger.d("pw:" + pw + " ;ph:" + ph);
RectFloat pixelRectFloat = new RectFloat(offX, offY, pw + offX, ph + offY);
canvas.drawPixelMapHolderRect(new PixelMapHolder(pixelMap), pixelRectFloat, mPixelMapPaint);
}
}
Отрисовка изображения в методе onDraw
drawPixelMap(canvas);
Определите начальную точку, конечную точку и выберите произвольную контрольную точку.
// Начальная точка
private Point start = new Point(0, 0);
// Конечная точка
private Point end = new Point(400, 0);
// Контрольная точка
private Point control = new Point(200, 200);
Кривая Бéзье
@Override
public void onDraw(Component component, Canvas canvas) {
canvas.save();
canvas.translate(mCoo.getPointX(), mCoo.getPointY());
drawHelpElement(canvas); // Рисование вспомогательных элементов - контрольных точек и базовых точек
// Рисование кривой Бéзье
mBezierPath.moveTo(start.getPointX(), start.getPointY());
mBezierPath.quadTo(control.getPointX(), control.getPointY(), end.getPointX(), end.getPointY());
canvas.drawPath(mBezierPath, mPaint);
mBezierPath.reset(); // Очистка mBezierPath
canvas.restore();
canvas.drawPicture(mPicture);
}
// Рисование вспомогательных элементов - контрольных точек и базовых точек
private void drawHelpElement(Canvas canvas) {
// Рисование точек данных и контрольных точек
mHelpPaint.setColor(new Color(0x8820ECE2));
mHelpPaint.setStrokeWidth(20);
canvas.drawPoint(start.getPointX(), start.getPointY(), mHelpPaint);
canvas.drawPoint(end.getPointX(), end.getPointY(), mHelpPaint);
canvas.drawPoint(control.getPointX(), control.getPointY(), mHelpPaint);
// Рисование вспомогательных линий
resetHelpPaint();
canvas.drawLine(start.getPointX(), start.getPointY(), control.getPointX(), control.getPointY(), mHelpPaint);
canvas.drawLine(end.getPointX(), end.getPointY(), control.getPointX(), control.getPointY(), mHelpPaint);
}
Метод поиска контрольной точки, который позволяет найти начальную точку, конечную точку и контрольную точку.```java @Override public boolean onTouchEvent(Component component, TouchEvent touchEvent) { // Обновление контрольной точки по положению касания и обновление экрана MmiPoint point = touchEvent.getPointerPosition(touchEvent.getIndex()); control.modify(point.getX() - mCoo.getPointX(), point.getY() - mCoo.getPointY()); Logger.d("touch control x:" + control.getPointX() + " y:" + control.getPointY()); invalidate(); return true; }
Печать точки касания

Эффект и практическое применение
|  |  |
| --------------------------- | ------------- |
### 4. Анимация процесса рисования Реализация анимации в начале
> Ранее использовался AnimatorValue, но выяснилось, что это возможно только начиная с API 7, и у нас много отрезков. Позже был использован EventHandler для пошагового рисования.
```java
EventRunner runnerA = EventRunner.getMainEventRunner();
EventHandler handlerA = new EventHandler(runnerA) {
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (drawStep == 0) {
drawStep = 1;
}
invalidate();
if (!drawLast) {
handlerA.sendEvent(1, 10);
}
}
};
public void startDraw() {
Logger.d(":");
if (drawLast) {
drawStep = 0;
handlerA.sendEvent(1);
drawLast = false;
}
}
Пошаговое рисование
Постоянное изменение шага childStep изменяет эффект каждого шага рисования
PathMeasure pathMeasure = new PathMeasure(mBezierPath, false);
childStep = pathMeasure.getLength();
// Использование пунктирного стиля кисти и смещения
PathEffect effect = new PathEffect(
new float[]{pathMeasure.getLength(), pathMeasure.getLength()},
childStep);
mPaint.setPathEffect(effect);
canvas.drawPath(mBezierPath, mPaint);
```## Заключение
1. Подтверждение центральной точки и создание координатной системы позволяет быстро разрабатывать;
2. В данной статье используется кривая Безье второго порядка для рисования. На основе первого шага, в событии touch находятся относительные координаты.
## Адрес кода
[bingdwendwen: HarmonyOS JAVA — пошаговое руководство по рисованию Bing Dwen Dwen (gitee.com)](https://gitee.com/guangdong-wangduoyu/bingdwendwen)
## Больше оригинальных материалов смотрите на: [HarmonyOS Academy](https://harmonyos.51cto.com/column/59)
От базы до мастерства, от техник до примеров, систематическое представление технологий разработки HarmonyOS. Приглашаем к публикации и подписке, вместе создадим экосистему HarmonyOS.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )