Привет, Хабр!
Вступление
В этой статье я буду рассказывать о создании своей IDE для Android. Я не нашел какого-либо материала на эту тему. Хочу разделить статью на несколько подстатей, так как информации будет много. Также буду оставлять ссылки на весь материал который я использовал.
Статья предназначена для новичков, ну и для тех кто хочет создать свою IDE для мобилки. Мы будем делать IDE для языка программирования Kotlin, но это не имеет особого значения, так как в проект можно будет добавить любой язык.
Также нам понадобятся библиотеки MaterialDesign и AndroidX, для создания красивого интерфейса, ну они часто уже есть в проектах по умолчанию, А также SoraEditor для создания удобного редактора с оптимизированой подсветкой синтаксиса.
Подготовка
Для начало подключим все нужные библиотеки. Заходим в файл app/build.gradle, и добавляем нужные зависимости:
dependencies {
implementation("com.google.android.material:material:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.1")
// sora editor API
// implementation(platform("io.github.Rosemoe.sora-editor:bom:0.23.2"))
// implementation 'io.github.Rosemoe.sora-editor:editor'
// implementation 'io.github.Rosemoe.sora-editor:language-textmate'
// Временно отключим
}
Пока-что зависимости SoraEditor нам не понадобятся, его мы будем использовать при создании самого редактора.
Также нужно поменять версию Java минимум на 17 для работы SoraEditor. В файле app/build.gradle:
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
...
}
Также, я отключу viewbinding, так как мне не нравится его использовать, но если вам он нравится, можете оставить.
Создадим класс App он будет наследоваться от Application, он будет хранить различные константы и общие данны, такие как путь к папке с проектами.
Мы будем хранить проекты во внутреннем хранилище, которое будт доступно всем приложениям. Конечно можно хранить и во внешнем, но не виду смысла заморачиваться на этот счет, я всеровно сделаю экспорт проекта в формате ZIP архива.
Пример класса App:
public class App extends Application {
private static Context context;
public static Context getContext() {
return context;
}
public static File getProjectsDir() {
File dir = new File(context.getExternalFilesDir(null), "projects/");
if(!dir.exists()) dir.mkdirs();
return dir;
}
}
Далее в манифесте, в <application> добавляем тег android:name=".App", псли ваш класс находится в другом пакете, то укажите другой пакет. Пример:
<application
android:name=".App">
...
</application>
Создание меню проектов
Создайте активность если вы ее еще не создали, я назову свою ProjectsActivity, и она будет находится в пакете .activitys для большего удобства, там будут находится все активности приложения.
В разметке этой активности, мы должны добавить 2 view, это Toolbar и RecyclerView.
Toolbar - это верхняя панель в приложении, которая является более гибкой версией ActionBar и AppBar, так мы может расположить ее в любом месте, но я уже по привычке его использую, вы можете использовать свой Toolbar.
RecyclerView - это улучшеная версия ListView, которая дополнительна оптимизирована для большого массива данных, так как использует минимальное кол-во элементов которые можно показать на экране, его рекомендуется использовать.
Вот пример разметки:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/toolbar"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/projects"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Я храню все цвета в файле colors.xml, чтоб можно было поменять в любой момент не бегая по файлам, в также чтобы удобно было делать что-то для другой темы, тоже самое с strings.xml но для языков. Я это написал потому-что многие не соблюдают эти обычаи.
Далее, нужно создать адаптер, а также сам элемент проекта в layout/.
Я создам дирректорию project, там будут все с этим связаные файле. Там создадим класс Project, для удобного использования, там будет хранится название проекта и путь к нему. Пример кода:
public class Project {
private String name;
private File path;
public Project(File path) {
this.path = path;
this.name = path.getName();
}
public Project(String name) {
this.name = name;
this.path = new File(App.getProjectsDir(), name);
}
public boolean create() {
File main = new File(path, "main.lua");
try {
main.createNewFile();
} catch(IOException e) {
e.printStackTrace();
return false;
}
return path.mkdirs();
}
// Другие методы...
}
Далее создаем адаптер. Создадим класс ProjectsAdapter, и наследуем RecyclerView.Adapter<ProjectsAdapter.VH>. VH это класс который мы должны создать для хранения View в каждом элементе в списке он наследуется от RecyclerView.ViewHolder. В моем будет хранится TextView и ImageView для создания меню с выбором действие, например удалить или переименовать.
В адаптере нужно переопределить несколько методов, это onCreateViewHolder(ViewGroup, int), onBindViewHolder(VH, int) и getItemCount().
onCreateViewHolder - в нес воздается поверхность (ViewHolder).
onBindViewHolder - тут обычно идет остальная настрока каждого элемента списка.
getItemCount - возвращает размер списка с элементам.
Пример адаптера
public class ProjectsAdapter extends RecyclerView.Adapter<ProjectsAdapter.VH> {
public class VH extends RecyclerView.ViewHolder {
private View parent;
public VH(View parent) {
super(parent);
this.parent = parent;
name = parent.findViewById(R.id.name);
more = parent.findViewById(R.id.more);
}
private TextView name;
private ImageView more;
}
private List<Project> list;
private Context context;
public ProjectsAdapter(Context context, List<Project> list) {
this.context = context;
this.list = list;
}
@Override
public VH onCreateViewHolder(ViewGroup parent, int pos) {
View view = LayoutInflater.from(context).inflate(R.layout.project_item, parent, false);
return new VH(view);
}
@Override
public void onBindViewHolder(VH vh, int pos) {
vh.name = list.get(pos).getName();
}
@Override
public int getItemCount() {
return list.size();
}
public void updateList(List<Project> list) {
this.list = list;
notifyDataSetChanged(); // говорим адаптеру что весь список изменился
}
}
В App я добавлю метод getProjects() который будет возвращать List<Project>
public static List<Project> getProjects() {
List<Project> projects = new ArrayList<>();
for(File file : getProjectsDir().listFiles()) {
if(file.isDirectory()) projects.add(file);
}
return projects;
}
В ProjectsActivity в методе onCreate, мы создать адаптер, и применить его к RecyclerVie
Пример
ProjectsAdapter adapter;
RecyclerView rv
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rv = findViewById(R.id.projects);
adapter = new ProjectsAdapter(this, App.getProjects());
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(adapter);
}
public void updateProjects() {
adapter.updateList(App.getProjects());
}
Управление проектами реализуем в следующей статье. Если будут вопросы можете задать их в комментариях.
Пока, Хабр! :-)