This article was translated from the Butter Knife
official website: butterknife
Brief introduction
Use @bind to annotate a field and butter knife to find and automatically convert to a view that matches your layout based on the given view ID.
Activity Binding
The activity binding sample code is as follows:
class ExampleActivity extends Activity { @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... }}
Instead of slow reflection, the code usually behaves like a view. Call bind to delegate these generic codes you can see and Debug.
The common code in the above example generates the code that looks like this:
public void bind (exampleactivity activity) {Activity = (android.widget ) Activity.findviewbyid ( 2130968578 ) ; Activity.footer = (android.widget Span class= "Hljs-preprocessor". TextView ) Activity.findviewbyid ( 2130968579 ) ; Activity.title = (android.widget Span class= "Hljs-preprocessor". TextView ) Activity.findviewbyid ( 2130968577 ) ; }
Non-activity binding (binds to inflate view)
You can also support your own view root by binding on custom objects.
publicclass FancyFragment extends Fragment { @Bind(R.id.button1) Button button1; @Bind(R.id.button2) Button button2; @OverridepubliconCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { false); ButterKnife.bind(this, view); // TODO Use fields... return view; }}
Binding to the View Holder
Public class myadapter extends baseadapter { @Override PublicViewGetView(intPosition, view view, ViewGroup parent) {Viewholder holder;if(View! =NULL) {holder = (Viewholder) view.gettag (); }Else{view = Inflater.inflate (R.layout.whatever, parent,false); Holder =NewViewholder (view); View.settag (holder); } holder.name.setText ("John Doe");//etc ... returnView }StaticClass Viewholder {@Bind(r.id.title) TextView name;@Bind(R.id.job_title) TextView JobTitle; Public Viewholder(View view) {Butterknife.bind ( This, view); } }}
You can see the specific application of these techniques in the examples provided above:
You can call Butterknife.bind from anywhere instead of calling Findviewbyid.
Other available binding APIs:
Binds a custom object, using an activity as the view root node. If you use a pattern like MVC, you can use its activity to bind the controller, with butterknife.bing (this, activity).
Use Butterknife.bind (this) to bind a view's child node field. You can call this method immediately if you use a node in your layout or a custom view constructor that uses inflate. Alternatively, a custom view type that is reflected from XML can be used in the Onfinishinflate callback method.
VIEW LISTS
You can organize complex views into a list or array.
@Bind({ R.id.first_name, R.id.middle_name, R.id.last_name })List<EditText> nameViews;
apply
method allows you to manipulate all the view in the list.
ButterKnife.apply(nameViews, DISABLE);ButterKnife.apply(nameViews, ENABLED, false);
Action
and Setter
interfaces allow you to specifically declare simple performance
static final butterknife.action<view> DISABLE = new butterknife.action<view> () { Span class= "hljs-annotation" > @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); }};
Android Property
(configuration information) can also be used in apply
methods, as apply
parameters of the method.
ButterKnife.apply(nameViews, View.ALPHA0.0f);
LISTENER BINDING
The listener can also be automatically configured into the method:
@OnClick(R.id.submit)publicvoidsubmit(View view) { // TODO submit data to server...}
All parameters of the listening method can be manipulated:
@OnClick(R.id.submit)publicvoidsubmit() { // TODO submit data to server...}
Define a specific type and it will be automatically converted by type
@OnClick(R.id.submit)publicvoidsayHi(Button button) { button.setText("Hello!");}
Declaring multiple IDs in a separate binding for a common event operation
@OnClick({ R.id.door1, R.id.door2, R.id.door3 })public void pickDoor(DoorView door) { if (door.hasPrizeBehind()) { Toast.makeText"You win!", LENGTH_SHORT).show(); } else { Toast.makeText"Try again", LENGTH_SHORT).show(); }}
Custom view can be tied to their own listener and does not need to specifically declare an ID.
publicclass FancyButton extends Button { @OnClick publicvoidonClick() { // TODO do something! }}
BINDING RESET
Fragment have different life cycles compared to activity. When binding in a fragment Oncreateview, you need to set the views to null in Ondestoryview. However, Butter knife has a Unbind method to do this automatically.
Public class fancyfragment extends Fragment { @Bind(R.id.button1) Button button1;@Bind(r.id.button2) Button button2;@Override PublicViewOncreateview(Layoutinflater inflater, ViewGroup container, Bundle savedinstancestate) {View view = Inflater.inflate (R.layout.fancy_fragment, container,false); Butterknife.bind ( This, view);//TODO use fields ... returnView }@Override Public void Ondestroyview() {Super. Ondestroyview (); Butterknife.unbind ( This); }}
OPTIONAL BINDINGS
By default, the bindings for @Bind and listeners are mandatory. If the target view is not found, an exception will be thrown.
To suppress this behavior and create an optional binding, add a @nullable annotation to the field or method
Note: Any annotations named @nullable can be used in this way. Encourage you to use the @nullable annotations in Android's own annotation library "Support-annotations", see Android Tools Project.
@Nullable @Bind(R.id.might_not_be_there) TextView mightNotBeThere;@Nullable @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() { ...}
Multi-method LISTENERS
Listeners that match method annotations have multiple callbacks that can be used to bind to any one of them. Each annotation has a default callback bound to it. You can use callback
parameters to declare an alternative callback.
@OnItemSelected(R.id.list_view)void onItemSelected(int position) { ...}@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)void onNothingSelected() { ...}
BONUS
Butter Knife also includes the FindByID method, which can still be used to find the target view in a view, Activity, or dialog.
It usually infers the type of the return value and then automatically casts the type.
View view = Layoutinflater. from(context). Inflate(R. Layout. Thing, null);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);ADDA static import for Butterknife. FindByID andEnjoy even more fun.
Download
Butter knife v7.0.1 JAR Download
Butter Knife Github Address
Butter Knife Java Docs Address
Maven
If you compile with MAVEN, you can declare the library as your dependency
<dependency> <groupId>com.jakewharton</groupId> <artifactId>butterknife</artifactId> <version>7.0.1</version></dependency>
GRADLE
Compile ' com.jakewharton:butterknife:7.0.1 '
Be sure to suppress this lint warning in your Build.gradle file.
lintOptions { disable‘InvalidPackage‘}
Some configurations may also require separate processing
{ exclude ‘META-INF/services/javax.annotation.processing.Processor‘}
IDE CONFIGURATION
Some ides require additional configuration in order for annotations to be able to use the
- IntelliJ idea--If your project uses additional configuration (such as Maven's Pom.xml), then the annotation process will work. If not, try manual configuration
- eclipse--Setting Manual Configuration
Proguard
Butter knife dynamic generation and use of class, which means that static analysis tools like Proguard may think this is useless. In order to prevent them from being removed, it is clearly indicated that they will be kept. To prevent Proguard from renaming class, a @bind is used in the class to annotate a member variable, so you need to use Keepclasseswithmembernames.
The obfuscation code is as follows
-keep class butterknife.** { *; }-dontwarn butterknife.internal.**-keep class **$$ViewBinder { *; }-keepclasseswithmembernames class * { @butterknife.* <fields>;}-keepclasseswithmembernames class * { @butterknife.* <methods>;}
Summarize
The problems encountered in the project are as follows:
In the open source Chinese source code, Butter Knife uses: Butterknife.inject (this)
@InjectView(R.id.quick_option_iv) @Override protectedvoidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ButterKnife.inject(this); }
While reading the official website Doc, found that the method does not exist, but is: Butterknife.bind (this)
@Bind (R. ID. TV1) TextView TV1;@Bind (R. ID. TV2) TextView TV2;@Bind (R. ID. TV3) TextView TV3;@Override protected void OnCreate (Bundle savedinstancestate) {Super. OnCreate(savedinstancestate);Setcontentview (R. Layout. Activity_main);Butterknife. Bind(this);Tv1. SetText("TV1");Tv2. SetText("TV2");Tv3. SetText("TV3");}
And the test inject in the code can not be used, and later found the reason:
- --butterknife-6.1.0.jar is used in open source China.
- The Official document is--butterknife-7.0.1.jar
Find the answer, this should be a version issue
About this kind of annotation, actually I do not like, the use of shortcut keys is not very troublesome, on the contrary, I always worry about excessive use of butterknife instead of looking for components to bring additional overhead, in short, there is a degree of the line
Open source Chinese source learning (vi) use of--butterknife