Библиотека Butter Knife позволит вам избежать большого количества однотипного кода, связанного с работой с View элементами в ваших Activity, фрагментах, холдерах и т.д. В этом материале я подробно рассмотрю возможности библиотеки, и на примерах покажу, как вы можете ее использовать.

 

 

Зачем нужен Butter Knife

 

Рассмотрим простой пример. Бывает необходимость показывать/скрывать сразу несколько View в Activity. В стандартном варианте реализации это может выглядеть так:

public class MainActivity extends AppCompatActivity {

    private List<View> viewList = new LinkedList<>();

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

        viewList.add(findViewById(R.id.title));
        viewList.add(findViewById(R.id.value));
        viewList.add(findViewById(R.id.loading));

        for (View view : viewList) {
            view.setVisibility(View.INVISIBLE);
        }

    }

}

Объявление списка, поиск элементов по findViewById и добавление в список, перебор списка и установка видимости.

 

А вот реализация с использованием Butter KnifeRetrolambda)

public class MainActivity extends AppCompatActivity {

    @BindViews({R.id.title, R.id.value, R.id.loading}) List<View> viewList;

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

        ButterKnife.apply(viewList, (view, value, index) -> view.setVisibility(value), View.INVISIBLE);
    }

}

Объявление списка, поиск элементов по findViewById и добавление в список - все это выполнила аннотация @BindViews, избавив нас от написания нескольких строк однотипного кода.

А комбинация Butter Knife + Retrolambda позволила одой строкой поменять видимость всем View в списке.


Кроме биндинга View элементов, библиотека умеет вешать на View различные обработчики, выполнять операции над коллекциями View и биндить значения из values. Давайте на примерах рассмотрим все эти возможности.

 

 

 

Подключение к проекту

 

Для подключения библиотеки к проекту необходимо добавить строки в dependencies в gradle файл модуля

compile 'com.jakewharton:butterknife:8.6.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'

  

 

 

View Binding

 

BindView

 

Аннотация BindView избавит вас от необходимости писать строки с findViewById.

Рассмотрим пример. В layout файле описан TextView:

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

 

Используем BindView, чтобы получить доступ к этому TextView в Activity:

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.title)
    TextView textViewTitle;

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

        textViewTitle.setText("bla bla");
    }

}

При работе с BindView от нас требуется указать id TextView элемента и переменную, в которую необходимо этот TextView поместить.

А в onCreate необходимо вызвать метод ButterKnife.bind и передать туда Activity. Этот метод найдет все Butter Knife аннотации в Activity и выполнит необходимые действия. В нашем случае он увидит аннотацию BindView, возьмет R.id.title, найдет TextView и поместит в textViewTitle.

После вызова ButterKnife.bind мы можем работать с textViewTitle.

 

Вместо типа переменной TextView, вы можете указать View. BindView автоматически выполнит для вас преобразование типа.

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.title)
    View viewTitle;

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

        viewTitle.setVisibility(View.INVISIBLE);
    }

}

 

Использование BindView для нескольких View элементов выглядит так:

@BindView(R.id.title)
TextView textViewTitle;

@BindView(R.id.value)
EditText editTextValue;

@BindView(R.id.loading)
ProgressBar progressBarLoading;

После вызова ButterKnife.bind все эти переменные будут заполнены и готовы к работе.

 

Если вы используете Butter Knife в фрагментах, то необходимо использовать Unbinder из-за особенностей Fragment Lifecycle.

public class MyFragment extends Fragment {

    private Unbinder unbinder;

    @BindView(R.id.title)
    TextView textViewTitle;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_my, container, false);
        unbinder = ButterKnife.bind(this, view);
        textViewTitle.setText("bla bla");
        return view;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }
}

В onCreateView вызываем bind и сохраняем полученный Unbinder объект в переменную unbinder. А в onDestroyView вызываем unbinder.unbind.

 

Также, вы можете использовать Butter Knife в холдерах при работе со списками:

    class Holder {
        @BindView(R.id.title)
        TextView textViewTitle;

        public Holder(View view) {
            ButterKnife.bind(this, view);
        }
    }

 

  

Nullable

 

По умолчанию, если BindView не найдет View с указанным id, то он вызовет Exception. Чтобы избежать этого, используйте аннотацию Nullable.

@Nullable @BindView(R.id.title)
TextView title;

 

 

BindViews

 

BindViews соберет указанные View в список или в массив.

Примеры:

Собираем три различных View (TextView, EditText, ProgressBar) в список с общим типом - View

@BindViews({R.id.title, R.id.value, R.id.loading})
List<View> viewList;

 

Или в массив

@BindViews({R.id.title, R.id.value, R.id.loading})
View[] viewList;

 

 

Собираем два View (TextView, EditText) в список с общим типом - TextView.

@BindViews({R.id.title, R.id.value})
List<TextView> textViewList;

  

 

 

Обработчики

 

ButterKnife позволяет удобно назначать для View наиболее распространенные обработчики

 

 

OnClick

 

Реализация обработчика OnClickListener.

 

Пометив метод аннотацией OnClick мы указываем, что этот метод будет являться обработчиком клика на View

    @OnClick(R.id.save)
    void onSaveClick() {
        // ...
    }

Теперь, при клике на View с id = R.id.save будет вызван метод onSaveClick. И вам уже не надо писать ни findViewById, ни setOnClickListener. BindView в этом случае вам также не нужен.


Если необходимо передавать "кликнутый" View в этот метод, то просто добавьте View в параметры метода:

    @OnClick(R.id.save)
    void onSaveClick(View view) {
        // ...
    }

 

Если вам надо получить конкретный тип View, например, Button, то укажите его:

    @OnClick(R.id.save)
    void onSaveClick(Button view) {
        // ...
    }

 

Butter Knife позволяет назначить один обработчик нескольким View. 

    @OnClick({R.id.button1, R.id.button2, R.id.button3})
    void onSaveClick(View view) {
        switch (view.getId()) {
            case R.id.button1:
                // ...
                break;
            case R.id.button2:
                // ...
                break;
            case R.id.button3:
                // ...
                break;
        }
    }

 

 

OnCheckedChanged

 

Реализация обработчика OnCheckedChangeListener

 

Можно использовать, например, для чекбоксов, чтобы получать его checked-состояние

    @OnCheckedChanged(R.id.agree)
    void onAgreeChecked(boolean checked) {
        // ...
    }

При изменении значений чекбокса с id = R.id.agree, будет вызываться метод onAgreeChecked.


Параметры метода могут варьироваться. Например, можно получать непосредственно View, которое было “чекнуто”

    @OnCheckedChanged(R.id.agree)
    void onAgreeChecked(CompoundButton view) {
        // ...
    }

 

А можно получать и View и checked-значение

    @OnCheckedChanged(R.id.agree)
    void onAgreeChecked(CompoundButton view, boolean checked) {
        // ...
    }

 

 

OnTextChanged

 

Реализация TextWatcher

 

Интерфейс TextWatcher содержит следующие методы:

    TextWatcher textWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    };

 

По умолчанию, Butter Knife создает обработчик, соответствующий методу onTextChanged

    @OnTextChanged(R.id.value)
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // ...
    }

 

Если вам нужны два других метода, это делается так:

    @OnTextChanged(value = R.id.value, callback = BEFORE_TEXT_CHANGED)
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // ...
    }

    @OnTextChanged(value = R.id.value, callback = AFTER_TEXT_CHANGED)
    public void afterTextChanged(Editable s) {
        // ...
    }

В аннотации OnTextChanged вам необходимо с помощью параметра callback указать, какой именно метод вам необходим. А метод onTextChanged идет по умолчанию, поэтому для него можно не указывать callback.


Этот же прием с callback используется для других обработчиков, которые содержат два и более методов. Каждый из них содержит документацию, в которой все это описано.

Посмотреть документацию в Android Studio можно поставив курсор на нужную вам аннотацию и нажав CTRL+Q.

 

 

Прочие обработчики

 

Перечислю, какие еще аннотации вы можете использовать и каким обработчикам они соответствуют.

OnEditorAction - OnEditorActionListener
OnFocusChange - OnFocusChangeListener
OnItemClick - OnItemClickListener
OnItemLongClick - OnItemLongClickListener
OnItemSelected - OnItemSelectedListener
OnLongClick - OnLongClickListener
OnPageChange - OnPageChangeListener
OnTouch - OnTouchListener

 

 

Optional

 

По умолчанию, если аннотация обработчика не найдет View с указанным id, то она вызовет Exception. Чтобы избежать этого, используйте аннотацию Optional.

    @Optional @OnClick(R.id.button1)
    void onClick() {
        // ...
    }

 

 

 

Операции

 

Butter Knife может выполнять определенные операции над одним View или целой группой View. Для этого используется метод ButterKnife.apply. Его можно вызывать для одного View, списка View и массива View.

Операции бывают трех типов

 

 

Action

 

Если применить Action к группе View, он будет выдавать вам View по одному и указывать его индекс, а вы уже решаете, что с этим View делать.

Например, есть задача, собирать текст со всех EditText в один StringBuilder. Это можно реализовать так:

        ButterKnife.Action getTexts = new ButterKnife.Action<EditText>() {
            @Override
            public void apply(@NonNull EditText editText, int index) {
                stringBuilder.append(index).append(". ").append(editText.getText().toString()).append("\r\n")
                ;
            }
        };

        ButterKnife.apply(viewList, getTexts);

При создании Action, указываем, что тип View будет EditText. Внутри Action, в методе apply, мы будем получать по одному все наши EditText и их позиции в списке. Для каждого из них мы добавляем в StringBuilder индекс и текст.

Остается вызывать метод ButterKnife.apply и передать ему список EditText-ов и Action.

В итоге, Action будет применен ко всем EditText из списка viewList. И StringBuilder будет содержать пронумерованные тексты из всех EditText.

 

 

Property

 

С помощью Property вы можете быстро установить какое-либо свойство целой группе View.

Например, прозрачность.

ButterKnife.apply(viewList, View.ALPHA, 0.5f);

 

  

Setter

 

Похож на Action, но позволяет дополнительно передавать значение внутрь метода операции.

Например, мы можем создать Setter, который будет устанавливать видимость View.

        ButterKnife.Setter visibleSetter = new ButterKnife.Setter<View, Integer>() {
            @Override
            public void set(@NonNull View view, Integer value, int index) {
                view.setVisibility(value);
            }
        };

При создании, мы указываем тип View и тип значения которое будем передавать - Integer. В методе set мы получим View и его индекс (аналогично Action), а также значение Integer, которое будем использовать в методе setVisibility.

Использование этого сеттера выглядит так

ButterKnife.apply(viewList, visibleSetter, View.VISIBLE);

 

В метод apply передаем список View, сеттер и значeние View.VISIBLE. Сеттер прогонит через себя весь список View и для каждого выполнит метод setVisibility(View.VISIBLE).

А если хотим спрятать все View, то используем этот же сеттер, но с значением View.INVISIBLE

ButterKnife.apply(viewList, visibleSetter, View.INVISIBLE);

 

 

 

Value Binding

 

Кроме View вы можете биндить различные значения из папки values.

Например dimensions:

@BindDimen(R.dimen.activity_horizontal_margin)
float marginFloat;
@BindDimen(R.dimen.activity_horizontal_margin)
int marginInt;


Можно получить как float, так и int значение.


Существуют следующие аннотации для биндинга значений:

BindArray
BindBitmap
BindBool
BindColor
BindDimen
BindDrawable
BindFloat
BindInt
BindString

 

Я описал практически все возможности текущей версии Butter Knife. Если чего пропустил, или с выходом новой версии появилось что-то интересное, пишите на форуме - я дополню материал.

 

Plugin

Для Android Studio есть полезный плагин

https://github.com/avast/android-butterknife-zelezny

 

Он за вас сможет создать BindView и OnClick.

 

При использовании, убедитесь, что курсор стоит на layout файле.

 

 

 


Присоединяйтесь к нам в Telegram:

- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance 

- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня




Language

Автор сайта

Дмитрий Виноградов

Подробнее можно посмотреть или почитать.

Никакие другие люди не имеют к этому сайту никакого отношения и просто занимаются плагиатом.

Социальные сети

 

В канале я публикую ссылки на интересные и полезные статьи по Android

В чате можно обсудить вопросы и проблемы, возникающие при разработке



Группа ВКонтакте



Поддержка проекта

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal