-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Reducing View Boilerplate with Butterknife
Butterknife is a popular View "injection" library for Android. This means that the library writes common boilerplate view code for you based on annotations to save you time and significantly reduce the lines of boilerplate code written.
In particular, Butterknife addresses these common use cases:
- Eliminate
findViewById
calls by using@Bind
on fields. - Eliminate anonymous inner-classes for listeners by annotating methods with
@OnClick
and others. - Group multiple views in a list or array. Operate on all of them at once with actions, setters, or properties.
- Eliminate resource lookups by using resource annotations on fields.
This guide covers the most common usages of the library.
Butterknife uses compile-time annotations which means there is no additional cost at run-time. Instead of slow reflection, code is generated ahead of time. Calling bind delegates to this generated code that you can see and debug. This means that Butterknife does not slow down your app at all!
Using Gradle, add the following line to app/build.gradle
file:
compile 'com.jakewharton:butterknife:7.0.1'
Use gradleplease to get the latest version. See this page for alternate installation methods.
There are three major features of ButterKnife:
- Improved View Lookups
- Improved Listener Attachments
- Improved Resource Lookups
Eliminate findViewById
calls by using @Bind
on fields:
class ExampleActivity extends Activity {
// Automatically finds each field by the specified ID.
@Bind(R.id.title) TextView title;
@Bind(R.id.subtitle) TextView subtitle;
@Bind(R.id.footer) TextView footer;
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}
This can be done within Activity
, Fragment
, or Adapter
classes. For example, fragment usage would look like:
public class FancyFragment extends Fragment {
@Bind(R.id.button1) Button button1;
@Bind(R.id.button2) Button button2;
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
// When binding a fragment in onCreateView, set the views to null in onDestroyView.
// Butter Knife has an unbind method to do this automatically.
@Override public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
}
}
Within a ViewHolder
inside of a ListView
adapter:
public class MyAdapter extends BaseAdapter {
@Override public View getView(int position, View view, ViewGroup parent) {
ViewHolder holder;
if (view != null) {
holder = (ViewHolder) view.getTag();
} else {
view = inflater.inflate(R.layout.whatever, parent, false);
holder = new ViewHolder(view);
view.setTag(holder);
}
holder.name.setText("John Doe");
// etc...
return view;
}
static class ViewHolder {
@Bind(R.id.title) TextView name;
@Bind(R.id.job_title) TextView jobTitle;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}
This will save you the need to ever write findViewById
ever again!
Eliminate anonymous inner-classes for listeners by annotating methods with @OnClick
and others:
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}
We can attach multiple views to the same listener with:
@OnClick({ R.id.door1, R.id.door2, R.id.door3 })
public void pickDoor(DoorView door) {
if (door.hasPrizeBehind()) {
Toast.makeText(this, "You win!", LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Try again", LENGTH_SHORT).show();
}
}
The following event listeners are supported out of the box: OnClick
, OnLongClick
, OnEditorAction
, OnFocusChange
, OnItemClick
, OnItemLongClick
,OnItemSelected
, OnPageChange
, OnTextChanged
, OnTouch
, OnCheckedChanged
.
Eliminate resource lookups in your Java code by using resource annotations on fields:
class ExampleActivity extends Activity { @BindString(R.string.title) String title; @BindDrawable(R.drawable.graphic) Drawable graphic; @BindColor(R.color.red) int red; // int or ColorStateList field @BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact value) field // ... }
The following resource types are available: BindArray
, BindBitmap
, BindBool
,BindColor
,BindDimen
,BindDrawable
,BindInt
,BindString
.
There are two advanced features:
- Acting on Multiple Views In a List
- Type Inference for View Lookups
You can group multiple views into a List and perform actions on them as group:
// Group the views together
@Bind({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;
The apply
method allows you to act on all the views in a list at once:
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);
This requires writing Action
or Setter
interfaces allow specifying the action to perform:
static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
@Override public void apply(View view, int index) {
view.setEnabled(false);
}
};
static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View, Boolean>() {
@Override public void set(View view, Boolean value, int index) {
view.setEnabled(value);
}
};
An Android property can also be used with the apply
method.
ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
Included are findById
methods which simplify code for view lookups. It uses generics to infer the return type:
TextView firstName = ButterKnife.findById(view, R.id.first_name);
TextView lastName = ButterKnife.findById(view, R.id.last_name);
ImageView photo = ButterKnife.findById(view, R.id.photo);
Add a static import for ButterKnife.findById and enjoy even more fun.
Created by CodePath with much help from the community. Contributed content licensed under cc-wiki with attribution required. You are free to remix and reuse, as long as you attribute and use a similar license.
Finding these guides helpful?
We need help from the broader community to improve these guides, add new topics and keep the topics up-to-date. See our contribution guidelines here and our topic issues list for great ways to help out.
Check these same guides through our standalone viewer for a better browsing experience and an improved search. Follow us on twitter @codepath for access to more useful Android development resources.