Аннотация
В этой статье я расскажу о своем опыте работы с приложением для рисования. Объясняя, что я видел и что получилось в результате, я приведу полный пример того, как производительное приложение для рисования React Native может быть реализовано с использованием библиотеки React Native Skia.

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

Какие были остальные:

В чем заключалась моя задача:

Как вы можете видеть на второй диаграмме, карандаш находится на каркасном изображении, а эффекты карандаша (линии) должны быть под каркасом, и это была сложная часть этой задачи.

TL; DR; Если вам нравится вставлять код, вот оно.

Основное решение
Без какой-либо бесполезной дополнительной информации и объяснений, основным решением для таких требований является использованиеreact-native-skia. Я нашел несколько примеров рисования или реализаций React Native, но все они были очень плохо производительными и определенно не были надежными для производства. Эта статья очень полезна для понимания SVG в React Native и того, как он работает, и как разработчик может работать со свойствами SVG наряду с использованием обработчиков жестов.

Работа со Skia
Я прочитал много статей и примеров и заметил, что единственным решением будет использование react-native-skia. Наряду с этим я нашел статью, которая могла бы стать очень полезным образцом react-native-skia . Но тем не менее, мое основное требование осталось. Мне понадобился каркас в малярной штанге, но все образцы были реализованы пустой белой штангой.

Разговаривая с Уильямом Кандиллоном
В процессе разработки, читая исходные коды react-native-skia, я нашел несколько решений для решения моей основной проблемы, но в некоторых случаях они не работали так, как я хотел, поэтому мне пришлось поговорить с участниками react-native-skia о некоторых изменениях или задать некоторые вопросы, и я открыл вопрос и PR. К счастью, Undet, пиарщик, William Candillon, создатель react-native-skia, поговорил со мной и его гидом, я понял, хотя он не мог мне помочь ☹️. Я только что глубоко погрузился в исходный код, чтобы найти свое решение.

Что такое react-native-skia
Если вы посмотрите на skia.org, вы поймете, что это библиотека 2D-графики, которая служит графическим движком для Google Chrome и ChromeOS, Android и Flutter, и он был написан на C/C++ и William с использованием NDK, используемого внутри Android и iOS, и с использованием модулей React Native, которые использовали его функциональные возможности в среде React Native.

В конце концов
Да, после долгих исследований, чтения исходного кода и общения с участниками я обнаружил, что могу использовать Canvas компонентов, Canvas из react-native-skia не для SVG. А также компонент Path для карандаша и линий. Итак, мои результаты стали следующими кодами:

<Canvas ref={drawRef} style={styles.paintBoom} onTouch={touchHandler}>
  <Group>
    <Fill color={palette.white} />
    {lines?.map((line, index) => (
      <Path
        key={`line_${line.path.toSVGString()}_${index}`}
        style="stroke"
        strokeJoin="round"
        strokeCap="round"
        path={line.path}
        paint={line.paint}
        strokeWidth={line.paint.getStrokeWidth()}
        color={line.paint.getColor()}
      />
    ))}
    <PaintingBodyPen path={path} />
    {!!image && (
      <Image
        x={0}
        y={0}
        image={image}
        width={drawWidth}
        height={drawHeight}
        fit="contain"
      />
    )}
  </Group>
</Canvas>

Как видите, Canvas со свойством onTouch может выполнять функции карандаша, а его эффекты будут нарисованы paintingBodyPen компонентом.
Fill компонент играет роль фона, а рендеринг цикла — это часть lines. Наконец, компонент Image — это каркас, о котором я беспокоился.

Объяснение реквизита
Я должен объяснить некоторые реквизиты, чтобы прояснить их использование:

  • ref: этот объект ref взят из верхнего уровня контекста, и я перешел к использованию некоторых Canvas функций, таких как экспорт нарисованных вещей в виде изображения.
  • onTouch: это функция-обработчик, которая ожидает результат useTouchHandler и состоит из трех шагов: запуск, активация и завершение. Если вы посмотрите на коды, их легко понять.
  • onStart: в кодах начальных шагов попробуйте получить цвет и strokeWidth из хранилища и установить их в path и paint, что они были созданы с помощью useValue:
const path = useValue(Skia.Path.Make());
const paint = useValue(Skia.Paint());
  • onActive: игнорировать условие shouldPaint, оно пытается предотвратить рисование при открытии цветовой палитры или меню обводки. Внутри onActive он пытается вычислить текущую позицию карандаша и зарегистрировать ее внутри объекта path.
  • onEnd: на этом уровне пришло время добавить нарисованную линию в хранилище и историю, сбросить то, что нарисовал пользователь, и подготовить путь и нарисованное объект для обработки следующего касания. После обновления магазина новая линия будет добавлена ​​в стрелу, и пользователь не почувствует преобразования линии карандаша в один из элементов нарисованных линий.

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

Результат
Нет необходимости объяснять больше. Смотреть это:

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