Или как не сойти с ума в поисках решения простейшей проблемы будучи новичком.
В один ужасный день мой научный руководитель предложил мне поработать над одним проектом. Я не буду вдаваться в подробности, но каркасом для будущего мобильного приложения должно было служить приложение для рисования пальцем на экране смартфона. Я согласился. На следующий день, в поисках решения в русскоязычном сегменте интернета я сдался. Еще через день, я прибегнул к страшной черной магии. Я загуглил вопрос на английском. И даже в данной среде я нашел лишь небольшое количество информации, но там я встретил своего учителя-ситха. Он научил меня многому, но и многое для создания этого приложения было предпринято мною лично.
Я не думаю, что данную статью будут читать профессиональные разрабы (иначе меня забросают помидорами). Статья в первую очередь нужна для новичков. Здесь не будет глубоких разъяснений почему так или не так. Здесь не будет самописных библиотек или чего-то заумного. Новичкам стоит лишь повторять то что написано в статье как в алгоритме. Для тех кто хочет видеть это в видео-формате от индуса, в конце статьи будет ссылка. Опытным Джавистам и разрабам на Андроид Студио - большое спасибо что уделяете внимание новичкам, будем благодарны за помощь и совет.
Для начала о ресурсах которые мы будем использовать. Наш друг из Индии любезно заготовил нам пару картинок в .xml формате и дал на них ссылку под видео, оригинальная ссылка на его гугл диск работать перестала, поэтому для вас будет его копия.
https://drive.google.com/drive/folders/1lv3pwm4YSr1q-LdTnvdQSvCvWImRg7ow?usp=sharing
Далее-библиотеки. Нам нужны библиотеки:
SignatureView, которая собственно и будет позволять нам рисовать на экране https://github.com/zahid-ali-shah/SignatureView
AmbilWarna для выбора цвета нашей "ручки".
https://github.com/yukuku/ambilwarnaНаш азиатский друг эту тему не затрагивал, но есть некоторые сложности с их подключением, о которых речь пойдет далее.
В основном алгоритм их подключения и не сильно от остальных отличается. Берем те зависимости которые указаны в описании библиотеки на гитхабе, в нашем случае это зависимости: 'com.github.yukuku:ambilwarna:2.0.1' и 'com.kyanogen.signatureview:signature-view:1.2'. Заходим в Андроид студио, во ВТОРОЙ файл build.grandle(Module :app) и при помощи "implementation" вписываем две эти зависимости в dependencies.
Но, как и в анекдоте про Чапая и Петьку, есть нюанс. Библиотека SignatureView так просто не заработает. Заходим в файл settings.grandle и, первое, дописываем в repositiories jcenter(), второе, в конце файла приписываем include 'SignatureView-Example', 'signature-view'
(Только что вы сделали за пару минут то, что мой хилый мозг придумывал пол для.) После чего, мы все это дело синхронизируем, при помощи кнопки "Sync now" в правом верхнем углу. Ура, библиотеки подключены!
Теперь к объектам на сцене. Можете забить на режим дизайна, сразу переключайтесь либо в сплит (чтобы сразу видеть что меняется на сцене), либо в режим кода. Удаляйте TextView и замените те страшные строчки в самом первом объекте на Relative Layout.
Возвращаемся к нашему SignatureView на гитхабе и копируем следующие строки, вставляем в пространство между RelativeLayout:
<com.kyanogen.signatureview.SignatureView
android:id="@+id/signature_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/optionsHolder"
android:layout_marginBottom="0dp"
app:backgroundColor="#ffffff"
app:enableSignature="true"
app:penColor="#000000"
app:penSize="5dp"/>
Уже этот кусок кода позволит нам рисовать на экране.
Отвлечемся на секунду для того, чтобы закинуть ассеты картинок. В папку drawable, что находится в папке res, закидываем наши скачанные ассеты. Готово, теперь в ресурсах будут отображаться 2 эти картинки.
Обратно к Xml. Теперь надо сделать панельку с кнопками и другими управляющими элементами. Для этого будем использовать:
Слайдер для увеличения/уменьшения кисти
2 кнопки. Одна меняет цвет нашей кисти, вторая стирает все что было нарисовано.
Создаем LinearLayout со следующими параметрами:
android:id="@+id/optionsHolder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_alignParentBottom="true"
и еще 2 внутри него с:
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="4dp"
//для первого
android:layout_gravity="end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="4dp"
//для второго
Самый главный Linear нам нужен для того чтобы обернуть в него 2 другие. Первый будет содержать слайдер, второй - 2 кнопки.
Переключаем все внимание на первый внутренний Linear. В нем надо создать SeekBar и TextView. Итоговый вариант первого внутреннего Linear'a:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="4dp"
>
<SeekBar
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:id="@+id/penSize">
</SeekBar>
<TextView
android:id="@+id/TxtPenSize"
android:textColor="@color/black"
android:text="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
При работе в режиме сплит вы увидите следующее:
Ко второму Linear'у. Создаем 2 ImageButton, со следующими параметрами. Для первого:
android:id="@+id/btnEraser"
android:layout_width="0dp"
android:layout_height="70dp"
android:background="@color/white"
android:scaleType="center"
android:layout_weight="1"
android:src="@drawable/ic_eraser"
//это будет кнопка стирания всего с экрана
Для второго:
android:id="@+id/btnColor"
android:layout_width="0dp"
android:layout_height="70dp"
android:background="@color/white"
android:scaleType="center"
android:layout_weight="1"
android:src="@drawable/ic_color"
//это будет кнопка смены цвета ручки.
Итоговый вариант Xml кода:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.kyanogen.signatureview.SignatureView
android:id="@+id/signature_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/optionsHolder"
android:layout_marginBottom="0dp"
app:backgroundColor="#ffffff"
app:enableSignature="true"
app:penColor="#000000"
app:penSize="5dp"/>
<LinearLayout
android:id="@+id/optionsHolder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_alignParentBottom="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="4dp">
<SeekBar
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:id="@+id/penSize">
</SeekBar>
<TextView
android:id="@+id/TxtPenSize"
android:textColor="@color/black"
android:text="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
<LinearLayout
android:layout_gravity="end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="4dp">
<ImageButton
android:id="@+id/btnEraser"
android:layout_width="0dp"
android:layout_height="70dp"
android:background="@color/white"
android:scaleType="center"
android:layout_weight="1"
android:src="@drawable/ic_eraser">
</ImageButton>
<ImageButton
android:id="@+id/btnColor"
android:layout_width="0dp"
android:layout_height="70dp"
android:background="@color/white"
android:scaleType="center"
android:layout_weight="1"
android:src="@drawable/ic_color">
</ImageButton>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Сам интерфейс программы будет таким:
Ура, мы закончили с интерфейсом! Устали? Я тоже, но осталось чуть-чуть (нет).
Теперь к любимой части, java коду.
Для начала импорт необходимого всего(библиотек):
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import com.kyanogen.signatureview.SignatureView;
import yuku.ambilwarna.AmbilWarnaDialog;
Теперь объявляем все переменные, необходимые нам:
SignatureView signatureView;// объект для того чтобы рисовать
ImageButton imgEraser,imgColor;// 2 объекта кнопок
SeekBar seekBar;// слайдбар для изменения размера ручки
TextView txtpensize;// текст для пояснения
int defaultcolor;// стандартный цвет который мы используем на данный момент
Ну а теперь крепим все это к объектам из .XML, через ID-шников, которые мы им уже дали в коде XML
signatureView=findViewById(R.id.signature_view);//метод findViewById делает возможным поиск по айди элемента в XML
imgEraser=findViewById(R.id.btnEraser);
imgColor= findViewById(R.id.btnColor);
seekBar=findViewById(R.id.penSize);
txtpensize=findViewById(R.id.TxtPenSize);
defaultcolor= ContextCompat.getColor(MainActivity.this,R.color.black);//просто черный цвет
Далее к основному коду. Для начала Seek Bar. Обращаемся к seekBar.setOnSeekBarChangeListener и видим следующую картину:
Здесь нам нужена только функция onProgressChanged, где мы пишем следующие строки:
txtpensize.setText(progress+"dp");//то что мы будем видеть как подсказку
signatureView.setPenSize(progress);//смена размера кисти через функции библиотеки
seekBar.setMax(50);//максимальное значение seekbara
Далее кнопка для стирания всего с экрана. Для этого обращаемся к imgEraser.setOnClickListener, а точнее к функции внутри него - public void onClick(View v) после чего пишем- signatureView.clearCanvas();. По итогу мы получим:
Теперь к смене цвета. Для начала, за пределами функции OnCreate, создаем функцию openColorPicker. Создаем там новый AmbilWarnaDialog:
AmbilWarnaDialog ambilWarnaDialog = new AmbilWarnaDialog(this, defaultcolor, new AmbilWarnaDialog.OnAmbilWarnaListener()
Дополняем все это безобразие следующими строками:
Теперь вернемся к функции OnCreate и дополняем его следующими строками для вызовы данной функции и смены цвета:
imgColor.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openColorPicker();
}
});
Ура! Вы сделали приложение для простейшего рисования для андроид устройств (меня наконец-то покормят!). Осталось только скомпилировать код и установить на любое андроид устройство.
Извиняюсь за ублюдский шортс, ютуб не дает сохранить видео не в формате шортс(:). На моей демонстрации черный цвет из-за темы телефона (инверсия цветов), на ваших устройствах все будет ОК.
На этом все. Как и обещал - ссылка на индуса-учителя-ситха: https://youtu.be/xGrOHLk60q8, надеюсь, он будет полезен вам (научите делать якоря и оглавление для статьи, а то у меня лапки).