«Hijckr: незаконное присвоение ваших XML-тегов с 2018 года»

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

Начало работы: gradle

Для начала создайте новое приложение для Android и добавьте зависимость от библиотеки Hijckr в файл build.gradle:

dependencies {
    // ... 
    implementation 'com.justinangel:hijckr:1+'
}

Пример Hijckr: перенаправление тегов для всего приложения

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

В качестве тривиального примера предположим, что все наши теги ‹TextView /› xml должны создавать экземпляр com.my.AppTextView, который изменяет цвет текста на красный и размер шрифта на 18.

Мы начинаем с файла макета XML, используя ‹TextView /›.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</LinearLayout>

Затем мы создадим класс AppTextView.

public class AppTextView extends TextView {
    // .. c'tors 

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        this.setTextSize(28);
        this.setTextColor(Color.RED);
    }
}

Теперь пора окропить магией Hijckr. Сначала мы скажем Hijckr перенаправить все теги XML, принадлежащие TextView, в AppTextView. Мы настроим их перенаправление в пользовательском приложении onCreate ().

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        HijckrClassLoader.addGlobalClassRouting(TextView.class, AppTextView.class);
    }
}

Для другой части сказочной пыли Hijckr мы изменим нашу активность, чтобы наследовать от HijckrActivity в качестве базового класса вместо Activity.

import com.justinangel.hijckr.HijckrActivity;
public class MainActivity extends HijckrActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

И когда мы запускаем наше приложение, мы видим, что наш ‹TextView /› использует новый AppTextView, потому что текст красный, а размер шрифта равен 18.

Hijckr: перенаправление тегов для конкретных действий

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

В качестве тривиального примера предположим, что мы хотим, чтобы все ‹EditText /› в рамках определенного действия находили любые строки «:)» и заменяли их эмодзи 😀. Начнем с файла макета с тегом ‹EditText /›.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Type a smiley face"/>
</LinearLayout>

Затем мы пишем настраиваемый виджет, который наследуется от EditText и добавляет желаемое дополнительное поведение.

public class SmileyEditText extends EditText {
    // .. c'tors 
    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);

        if (text.toString().contains(":)")) {
            setText(text.toString().replace(":)", "\uD83D\uDE0A"));
        }
    }
}

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

import com.justinangel.hijckr.HijckrClassLoader;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public ClassLoader getClassLoader() {
        return new HijckrClassLoader(super.getClassLoader())
                .withClassRouting(EditText.class, S.class);
    }
}

Когда мы запускаем этот образец и набираем «:)», мы видим, что текст был заменен.

Когда мне следует использовать Hijckr? Какие лучшие практики?

Я использую перенаправление тегов в стиле Hijckr уже несколько лет, и мы разработали несколько лучших практик в наших приложениях.

  • Можно добавить поведение к существующим виджетам с помощью Hijckr, добавив код в c’tors или переопределив жизненный цикл Android.
  • Используйте конструктор и виджеты Android Studio по умолчанию. Hijckr позволяет вам продолжать использовать виджеты по умолчанию в конструкторе по умолчанию.
  • Не используйте Hijckr исключительно для стилизации. В Android есть отличная система управления ресурсами, которая поддерживает стили и темы. Вы не хотите отказываться от этого.
  • Можно использовать Hijckr для условного изменения стиля и поведения виджетов. Например, приложение, работающее на Android Wear с макетами, содержащими теги ‹RecyclerView /›, необходимо перенаправить на WearableRecyclerView. Это тот случай, который впервые привел меня в Hijckr.

Известные ограничения

  • Созданные элементы: изменение глобальной маршрутизации применяется только до расширения файлов макета. Он не будет применяться задним числом к ​​созданным элементам после расширения макета.
  • Именованные элементы: для элементов XML с x: перемаршрутизация имени должна выполняться в направлении классов, унаследованных от исходной маршрутизации. например ‹Button x: Name =” foo ”/› необходимо направить в класс, который имеет Button в качестве базового класса. Для любых XML-элементов, у которых нет x: перенаправление имени не имеет этих ограничений. Например, ‹Button /› можно направить на что угодно (например, TextView).

Вопросов?

Спрашивай.

Ознакомьтесь с исходным кодом на GitHub.