Android Butterknife (Butter Knife) Usage Summary

Android Butterknife (Butter Knife) Usage Summary

Preface:

ButterKnife is a View injection framework focused on the Android system. In the past, you always had to write a lot of findViewById to find the View object. With ButterKnife, you can easily save these steps. It is the masterpiece of the great god JakeWharton and is currently widely used. The most important point is that using ButterKnife has basically no performance loss, because the annotations used by ButterKnife are not reflected at runtime, but generate new classes at compile time. The project is also very convenient to integrate and very simple to use.

By studying this article, you will learn how to use ButterKnife in your project. This article contains the following points:

Preface

  1. Brief Introduction
  2. ButterKnife Advantages
  3. Basic Configuration
  4. ButterKnife registration and binding
  5. ButterKnife usage experience and precautions
  6. Bind ButterKnife in Activity
  7. Binding ButterKnife in Fragment
  8. Bind ButterKnife in Adapter
  9. Basic use of ButterKnife
  10. Binding View
  11. Binding Resources
  12. Event Binding
  13. Binding Listener
  14. Using findById
  15. Setting properties of multiple views
  16. Precautions for use
  17. More binding annotations
  18. More event notes
  19. ButterKnife's code obfuscation
  20. Butterknife plugin: zelezny
  21. Plugin Installation
  22. Plugin Usage

ButterKnife project address: https://github.com/JakeWharton/butterknife

▲ Advantages of ButterKnife:

  1. Powerful View binding and Click event processing functions to simplify code and improve development efficiency
  2. Conveniently handle ViewHolder binding issues in Adapter
  3. It will not affect the efficiency of APP during operation and is easy to use and configure
  4. The code is clear and readable

Basic Configuration

Configuring and using ButterKnife in an Android Studio project

Step one: Add the following code to the build.gradle file of the Project:

  1. buildscript {
  2. repositories {
  3. jcenter()
  4. }
  5. dependencies {
  6. classpath 'com.android.tools.build:gradle:2.3.3'  
  7. classpath 'com.jakewharton:butterknife-gradle-plugin:8.8.1' //Add this line
  8. }
  9. }

Step two: Add the following code to App's build.gradle:

  1. apply plugin: 'com.jakewharton.butterknife'  

Add in dependencies:

  1. compile 'com.jakewharton:butterknife:8.8.1'  
  2. annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'  

The construction environment is very simple. Next, let's see how to use it

ButterKnife registration and binding

▲ ButterKnife usage experience and precautions:

  1. Bind in the Activity class: ButterKnife.bind(this); must be bound after setContentView(); and after the parent class is bound, the subclass does not need to bind again.
  2. Binding in non-Activity classes (eg: Fragment, ViewHold): ButterKnife.bind(this, view); the this here cannot be replaced with getActivity().
  3. There is no need to unbind in Activity, but it must be unbinded in onDestroyView() in Fragment.
  4. Methods and controls modified with ButterKnife cannot be modified with private or static, otherwise an error will be reported. Error: @BindView fields must not be private or static. (com.zyj.wifi.ButterknifeActivity.button1)
  5. setContentView() cannot be implemented via annotations. (Some other annotation frameworks can)
  6. When using Activity to bind any object to the root view, if you use a design pattern like MVC, you can call ButterKnife.bind(this, activity) in Activity to bind the Controller.
  7. Use ButterKnife.bind(this, view) to bind a view's child node fields. If you use inflate in the child View's layout or in the custom view's constructor, you can call this method immediately. Alternatively, custom view types from XML inflate can use it in the onFinishInflate callback method.

▲ Bind ButterKnife in Activity:

Since you need to bind the Activity in onCreate every time, I suggest you write a BaseActivity to complete the binding, and then the subclass can inherit it. The Activity must be bound after setContentView. Use ButterKnife.bind(this) to bind. The code is as follows:

  1. public class MainActivity extends AppCompatActivity{
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. //Binding and initializing ButterKnife
  7. ButterKnife.bind(this);
  8. }
  9. }

▲ Bind ButterKnife in Fragment:

The life cycle of a fragment is different from that of an activity. When you bind a fragment in onCreateView, set the view to null in onDestroyView. When you call bind to bind a fragment for you, Butter Knife returns an instance of Unbinder. Call its unbind method in the appropriate life cycle (onDestroyView) callback to unbind the fragment. Use ButterKnife.bind(this, view) to bind. The code is as follows:

  1. public class ButterknifeFragment extends Fragment{
  2. private Unbinder unbinder;
  3. @Override
  4. public   View onCreateView(LayoutInflater inflater, ViewGroup container,
  5. Bundle savedInstanceState) {
  6. View   view = inflater.inflate(R.layout.fragment, container, false );
  7. //Return an Unbinder value (for unbinding). Note that this cannot use getActivity()
  8. unbinder = ButterKnife.bind(this, view );
  9. return   view ;
  10. }
  11.  
  12. /**
  13. * Perform unbinding operation in onDestroyView
  14. */
  15. @Override
  16. public void onDestroyView() {
  17. super.onDestroyView();
  18. unbinder.unbind();
  19. }
  20. }

▲ Bind ButterKnife in Adapter:

Use it in the ViewHolder of the Adapter, add a constructor to the ViewHolder, and pass the view into it when creating a new ViewHolder. Use ButterKnife.bind(this, view) to bind, the code is as follows:

  1. public class MyAdapter extends BaseAdapter {
  2.  
  3. @Override
  4. public   View getView( int position, View   view , ViewGroup parent) {
  5. ViewHolder holder;
  6. if ( view != null ) {
  7. holder = (ViewHolder) view .getTag();
  8. } else {
  9. view = inflater.inflate(R.layout.testlayout, parent, false );
  10. holder = new ViewHolder( view );
  11. view .setTag(holder);
  12. }
  13.  
  14. holder.name .setText( "Donkor" );
  15. holder.job.setText( "Android" );
  16. // etc...
  17. return   view ;
  18. }
  19.  
  20. static class ViewHolder {
  21. @BindView(R.id.title) TextView name ;
  22. @BindView(R.id.job) TextView job;
  23.  
  24. public ViewHolder( View   view ) {
  25. ButterKnife.bind(this, view );
  26. }
  27. }
  28. }

Basic use of ButterKnife

▲ Binding View:

Control id annotation: @BindView()

  1. @BindView( R2.id.button)
  2. public Button button;

Multiple control IDs in the layout Annotation: @BindViews()

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. @BindViews({ R2.id.button1, R2.id.button2, R2.id.button3})
  4. public List<Button> buttonList;
  5.  
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10.  
  11. ButterKnife.bind(this);
  12.  
  13. buttonList.get( 0 ).setText( "hello 1 " );
  14. buttonList.get( 1 ).setText( "hello 2 " );
  15. buttonList.get( 2 ).setText( "hello 3 " );
  16. }
  17. }

▲ Binding resources:

Bind string: @BindString()

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. @BindView(R2.id.button) //Bind button control
  4. public Button button ;
  5.  
  6. @BindString(R2.string.app_name) //Bind the string in the resource file
  7. String str;
  8.  
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_main);
  13. //Bind activity
  14. ButterKnife.bind( this );
  15. button.setText( str );
  16. }
  17. }

Bind the array in the string: @BindArray()

  1. <resources>
  2. <string name = "app_name" >City</string>
  3.  
  4. <string-array name = "city" >
  5. <item>Beijing City</item>
  6. <item>Tianjin</item>
  7. <item>Harbin</item>
  8. <item>Dalian City</item>
  9. <item>Hong Kong City</item>
  10. </string-array>
  11.  
  12. </resources>
  13.  
  14. ----------------------------------------------------------------------------------  
  15.  
  16. public class MainActivity extends AppCompatActivity {
  17.  
  18. @BindView(R2.id.button) //Bind button control
  19. public Button button ;
  20.  
  21. @BindString(R2.string.app_name) //Bind the string in the resource file
  22. String str;
  23.  
  24. @BindArray(R2.array.city) //Bind the array in string
  25. String [] cities;
  26.  
  27. @Override
  28. protected void onCreate(Bundle savedInstanceState) {
  29. super.onCreate(savedInstanceState);
  30. setContentView(R.layout.activity_main);
  31. //Bind activity
  32. ButterKnife.bind( this );
  33. button.setText(citys[0]);
  34. }
  35. }

Bind Bitmap resource: @BindBitmap()

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. @BindView( R2.id.imageView ) //Bind the ImageView control
  4. public ImageView imageView ;
  5.  
  6. @BindBitmap(R2.mipmap.bm) //Bind Bitmap resources
  7. public Bitmap bitmap ;
  8.  
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_main);
  13.  
  14. //Bind activity
  15. ButterKnife.bind( this );
  16.  
  17. imageView.setImageBitmap(bitmap);
  18. }
  19.  
  20. }

Bind a color value: @BindColor()

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. @BindView( R2.id.button) //Bind a control
  4. public Button button;
  5.  
  6. @BindColor( R2.color.colorAccent ) //Specific color value is in the color file
  7. int black ; //bind a color value
  8.  
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_main);
  13.  
  14. //Bind activity
  15. ButterKnife.bind( this );
  16.  
  17. button.setTextColor( black );
  18. }
  19. }

▲ Event binding:

Bind click event:

  • Bind control click event: @OnClick()
  • Bind control long press event: @OnLongClick()
  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. @OnClick(R2.id.button1 ) //Set a click event for button1
  4. public void showToast(){
  5. Toast.makeText(this, "is a click" , Toast.LENGTH_SHORT).show();
  6. }
  7.  
  8. @OnLongClick( R2.id.button1 ) //Set a long press event for button1
  9. public boolean showToast2(){
  10. Toast.makeText(this, "is a long click" , Toast.LENGTH_SHORT).show();
  11. return   true ;
  12. }
  13.  
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_main);
  18.  
  19. //Bind activity
  20. ButterKnife.bind( this );
  21. }
  22. }

Specify multiple id binding events:

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. //Tip: When it comes to binding multiple id events, we can use Butterknife of Android studio
  4. //The plugin zelezny is generated automatically and quickly. The installation and use of the plugin will be introduced below.
  5. @OnClick({R.id.ll_product_name, R.id.ll_product_lilv, R.id.ll_product_qixian, R.id.ll_product_repayment_methods})
  6. public void onViewClicked( View   view ) {
  7. switch ( view .getId()) {
  8. case R.id.ll_product_name:
  9. System.out.print ( "I am click event 1" );
  10. break;
  11. case R.id.ll_product_lilv:
  12. System.out.print ( "I am click event 2" );
  13. break;
  14. case R.id.ll_product_qixian:
  15. System.out.print ( "I am click event 3" );
  16.  
  17. break;
  18. case R.id.ll_product_repayment_methods:
  19. System.out.print ( "I am click event 4" );
  20. break;
  21. }
  22. }
  23.  
  24. @Override
  25. protected void onCreate(Bundle savedInstanceState) {
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.activity_main);
  28.  
  29. //Bind activity
  30. ButterKnife.bind( this );
  31. }
  32. }

From the above example, we can see that multiple click events cannot be written in R2. If you must use R2, you can write them one by one. The correct way to write them is as follows:

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. @OnClick(R2.id.ll_product_name)
  4. public void onViewClicked1( View   view ) {
  5. System.out.print ( "I am click event 1" );
  6. }
  7. @OnClick(R2.id.ll_product_lilv)
  8. public void onViewClicked2( View   view ) {
  9. System.out.print ( "I am click event 2" );
  10. }
  11. @OnClick(R2.id.ll_product_qixian)
  12. public void onViewClicked3( View   view ) {
  13. System.out.print ( "I am click event 3" );
  14. }
  15. @OnClick(R2.id.ll_product_repayment_methods)
  16. public void onViewClicked4( View   view ) {
  17. System.out.print ( "I am click event 4" );
  18. }
  19.  
  20. @Override
  21. protected void onCreate(Bundle savedInstanceState) {
  22. super.onCreate(savedInstanceState);
  23. setContentView(R.layout.activity_main);
  24.  
  25. //Bind activity
  26. ButterKnife.bind( this );
  27. }
  28. }

Custom View uses binding events

No need to specify an id, just annotate OnClick. Looking at the code, it seems to be similar to the method of implementing a click event. In fact, the OnClickListener interface is not implemented. The code is as follows:

  1. public class MyButton extends Button {
  2. @OnClick
  3. public void onClick() {}
  4. }

▲ Binding monitoring:

Listeners can be automatically configured into methods

  1. @OnClick(R.id.submit)
  2. public void submit( View   view ) {
  3. // TODO submit data to server...
  4. }

All parameters to listener methods are optional

  1. @OnClick(R.id.submit)
  2. public void submit() {
  3. // TODO submit data to server...
  4. }

Customize a specific type and it will be converted automatically

  1. @OnClick(R.id.submit)
  2. public void sayHi(Button button) {//You will understand the changes in the parameters in the brackets
  3. button.setText( "Hello!" );
  4. }

Specify multiple ids in a single binding for common event handling. Here we use click event as an example. Other event listeners are also possible.

  1. @OnClick(R.id.submitCode,R.id.submitFile,R.id.submitTest)
  2. public void sayHi(Button button) {//Multiple controls correspond to common events
  3. button.setText( "Success!" );
  4. }

Custom views can bind to their own listeners by not specifying an ID.

  1. public class FancyButton extends Button {
  2. @OnClick
  3. public void onClick() {
  4. // TODO do something!
  5. }
  6. }

Multiple method annotations in Listener

Method annotations whose corresponding listeners have multiple callbacks that can be used to bind to any of them. Each annotation has a default callback that it is bound to. Use the callback parameter to specify a replacement. Take Spinner as an example.

Original code:

  1. Spinner s = new Spinner(this);
  2. //Original method: Spinner item selection listener event normal writing
  3. s.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){
  4. @Override
  5. public void onItemSelected(AdapterView<?> parent, View   view , int position, long id) {
  6. }
  7. @Override
  8. public void onNothingSelected(AdapterView<?> parent) {
  9. }
  10. });

Through Butter Knife annotation

  1. public class MainActivity extends AppCompatActivity {
  2. /*Use annotations to select and listen to the event processing method for the Spinner item*/
  3. @OnItemSelected(R.id.my_spiner) //The default callback is ITEM_SELECTED
  4. void onItemSelected( int position) {
  5. Toast.makeText(this, "position: " + position, Toast.LENGTH_SHORT).show();
  6. }
  7. /*
  8. * To annotate onNothingSelected, you need to add a callback to the annotation parameter.
  9. * Note that as long as there is data in the Spinner, the 0th data will be selected by default, so if you want to enter the onNothingSelected() method, you need to clear all the data in the Adapter
  10. */
  11. @OnItemSelected(value = R.id.my_spiner, callback = OnItemSelected.Callback.NOTHING_SELECTED)
  12. void onNothingSelected() {
  13. Toast.makeText(this, "Nothing" , Toast.LENGTH_SHORT).show();
  14. }
  15.  
  16. @Override
  17. protected void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.activity_main);
  20.  
  21. //Bind activity
  22. ButterKnife.bind( this );
  23. Spinner s=new Spinner(this);
  24. }
  25. }

Use of @OnCheckedChanged listener

The original method should be: setOnCheckedChangeListener(). Example

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"    
  3. android:layout_width= "match_parent"    
  4. android:layout_height= "match_parent"    
  5. android:orientation= "vertical" >
  6.  
  7. <RadioGroup
  8. android:id= "@+id/rg_main"    
  9. android:layout_width= "fill_parent"    
  10. android:layout_height= "48dp"    
  11. android:layout_alignParentBottom= "true"    
  12. android:background= "@color/white"    
  13. android:orientation= "horizontal" >
  14.  
  15. <RadioButton
  16. android:id= "@+id/rg_home"    
  17. android:layout_width= "match_parent"    
  18. android:layout_height= "match_parent"    
  19. android:focusable= "false"    
  20. android:text= "@string/nav_one" />
  21.  
  22. <RadioButton
  23. android:id= "@+id/rg_wealth"    
  24. android:layout_width= "match_parent"    
  25. android:layout_height= "match_parent"    
  26. android:focusable= "false"    
  27. android:text= "@string/nav_two" />
  28.  
  29. <RadioButton
  30. android:id= "@+id/rg_account"    
  31. android:layout_width= "match_parent"    
  32. android:layout_height= "match_parent"    
  33. android:focusable= "false"    
  34. android:text= "@string/nav_four" />
  35. </RadioGroup>
  36.  
  37. </LinearLayout>
  38.  
  39. -------------------------------------------------------------------------------  
  40.  
  41. @OnCheckedChanged({R.id.rg_home,R.id.rg_wealth,R.id.rg_account})
  42. public void OnCheckedChangeListener(CompoundButton view , boolean ischanged){
  43. switch ( view .getId()) {
  44. case R.id.rg_home:
  45. if (ischanged){//Note: This judgment must be made here. Only when the button corresponding to the id is clicked and the ischanged state changes, the following content will be executed
  46. //Write your button state change UI and related logic here
  47. }
  48. break;
  49. case R.id.rg_wealth:
  50. if (ischanged) {
  51. //Write your button state change UI and related logic here
  52. }
  53. break;
  54. case R.id.rg_account:
  55. if (ischanged) {
  56. //Write your button state change UI and related logic here
  57. }
  58. break;
  59. default :
  60. break;
  61. }
  62. }

▲ Using findById:

Butter Knife still includes the findById() method for when you still need to initialize a view from a view, Activity, or Dialog, and it can automatically convert types.

  1. View   view = LayoutInflater. from (context).inflate(R.layout.thing, null );
  2. TextView firstName = ButterKnife.findById( view , R.id.first_name);
  3. TextView lastName = ButterKnife.findById( view , R.id.last_name);
  4. ImageView iv = ButterKnife.findById( view , R.id.iv);

▲ Set the properties of multiple views:

apply()

Effect: Allows you to perform operations on all views in the list at once.

Action and Setter Interfaces

Purpose: Action and Setter interfaces allow simple behaviors to be specified.

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. @BindViews({R2.id.first_name, R2.id.middle_name, R2.id.last_name})
  4. List<EditText> nameViews;
  5.  
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10.  
  11. //Bind activity
  12. ButterKnife.bind(this);
  13.  
  14. //Set the properties of multiple views
  15. //Method 1: passing value
  16. ButterKnife.apply(nameViews, DISABLE);
  17. //Method 2: Specify a value
  18. ButterKnife.apply(nameViews, ENABLED, false );
  19. ////Method 3: Set the Property of View
  20. ButterKnife.apply(nameViews, View .ALPHA, 0.0f); //An Android attribute can also be used in application methods.
  21. }
  22.  
  23. /*
  24. * Action interface setting properties
  25. */
  26. static final ButterKnife. Action < View > DISABLE = new ButterKnife. Action < View >() {
  27. @Override
  28. public void apply( View   view , int   index ) {
  29. view .setEnabled( false ); //The purpose is to enable multiple views to have this attribute
  30. }
  31. };
  32. /*
  33. * Setter interface to set properties
  34. */
  35. static final ButterKnife.Setter< View , Boolean> ENABLED = new ButterKnife.Setter< View , Boolean>() {
  36. @Override
  37. public void set ( View   view , Boolean value, int   index ) {
  38. view .setEnabled(value); //The purpose is to enable multiple views to have this attribute. The variable Boolean value can be passed
  39. }
  40. };
  41. }

▲ Precautions for use:

ButterKinfe's annotation labels vary from version to version.

The Bind tag before 8.0.0 became BindView after 8.0.0, and after 8.7.0, when binding a view, you need to use R2.id.XXX instead of the commonly used R.id.XXX.

Specific changes and view the submission log on gitHub:

  • https://github.com/JakeWharton/butterknife/blob/master/CHANGELOG.md#version-800-2016-04-25

By default, @bind and listener binding are required. If the target view cannot be found, an exception will be thrown.

To suppress this behavior and create optional binding, you can add the @Nullable annotation to a field, or the @Optional annotation to a method.

Any annotation named @Nullable can be used for member variables. It is recommended to use the @Nullable annotation from the android "support-annotations" library.

  1. @Nullable
  2. @BindView(R.id.might_not_be_there)
  3. TextView mightNotBeThere;
  4.  
  5. @Optional
  6. @OnClick(R.id.maybe_missing)
  7. public void onMaybeMissingClicked() {
  8. // TODO ...
  9. }

▲ More binding notes:

  • @BindView—->Bind a view; id is a view variable
  • @BindViews —-> Bind multiple views; id is a list variable of a view
  • @BindArray—-> bind the array in string; @BindArray(R.array.city) String[] cities;
  • @BindBitmap—->Bind image resources to Bitmap; @BindBitmap( R.mipmap.wifi ) Bitmap bitmap;
  • @BindBool —-> Bind a boolean value
  • @BindColor —->Bind color;@BindColor(R.color.colorAccent) int black;
  • @BindDimen —->Bind Dimen;@BindDimen(R.dimen.borth_width) int mBorderWidth;
  • @BindDrawable —-> Bind Drawable; @BindDrawable(R.drawable.test_pic) Drawable mTestPic;
  • @BindFloat —->Bind float
  • @BindInt —-> Binds int
  • @BindString —->Bind a String id to a String variable; @BindString( R.string.app_name ) String meg;

▲ More event notes:

  • @OnClick—->Click event
  • @OnCheckedChanged —-> Check, Uncheck
  • @OnEditorAction —-> Function keys of the soft keyboard
  • @OnFocusChange —-> Focus changed
  • @OnItemClick item—-> is clicked (note that there is a pitfall here. If there are Button and other control events with click events in the item, you need to set the focusable property of these controls to false)
  • @OnItemLongClick item—->Long press (return true to intercept onItemClick)
  • @OnItemSelected —->item selected event
  • @OnLongClick —-> Long press event
  • @OnPageChange —->Page change event
  • @OnTextChanged —->Text change event in EditText
  • @OnTouch —->Touch event
  • @Optional —-> Selective injection. If the current object does not exist, an exception will be thrown. In order to suppress this exception, you can add an annotation to the variable or method to make the injection selective. If the target View exists, it will be injected. If it does not exist, nothing will be done.
  1. //Test @Optional
  2. @Optional
  3. @OnCheckedChanged(R.id.cb_test)
  4. public void onCheckedChanged(CompoundButton buttonView,boolean isChecked){
  5. if(isChecked){
  6. tvTest.setText( "Selected..." );
  7. } else {
  8. tvTest.setText( "Cancelled..." );
  9. }
  10. }

ButterKnife's code obfuscation

In the obfuscated file, add the following code:

  1. -keep class butterknife.** { *; }
  2. -dontwarn butterknife.internal.**
  3. -keep class **$$ViewBinder { *; }
  4.  
  5. -keepclasseswithmembernames class * {
  6. @butterknife.* <fields>;
  7. }
  8.  
  9. -keepclasseswithmembernames class * {
  10. @butterknife.* <methods>;
  11. }

Plugin Installation:

Go to File in the toolbar and find Settings… or use the shortcut Ctrl+Alt+s to open it. Search for zelezny, download the plugin and install it. Restart Android Studio

Plugin usage:

After installing the plugin, you will be prompted to restart AS. After restarting, you can write a layout and create a new code class for testing. During the test, please note that you need to move the cursor to setContentView(R.layout.acty_login), put the cursor in R.layout.acty_login, and then right-click Generate. Here is a gif effect chart to more intuitively show the advantages of the plugin. For multiple IDs that need to be bound, it saves the time of manually typing the code.

<<:  Qualcomm and Huawei are increasingly competing for the first 5G chip

>>:  The designer of the first iPhone pointed out this big flaw of the iPhone

Recommend

Breathing in liquid, from the deep sea to space

380 million years ago, fish began to crawl onto l...

Was global warming first proposed by astronomers?

Author | Zhou Yihao Review | Zheng Chengzhuo Edit...

Birds nesting in streetlights? Is this a better or worse life?

This is a street lamp in Shenzhen Futian Mangrove...

What should I pay attention to when renting a server?

What should I pay attention to when renting a ser...

Look at the wrinkles! The missing golden eyes of Black Myth: Wukong are here →

The Fiery Eyes and Golden Pupils originally refer...