​ 今天大体浏览了stormzhang的博客,学到了很多新知识,最主要的就是ButterKnife注入框架,在此记录一下使用方法。使用它可以简化代码,轻松绑定View和Listener。

Github开源地址:https://github.com/JakeWharton/butterknife

官方介绍:http://jakewharton.github.io/butterknife/

Android Studio 配置

​ 首先在Project级别的build.gradle添加 ‘android-apt’ lugin支持:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        //https://github.com/JakeWharton/butterknife
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

​ 然后在Module级别的build.gradle中应用‘android-apt’ lugin支持,并且添加Butter Knife dependencies:

apply plugin: 'android-apt'

android {
    ......
}

dependencies {
    //https://github.com/JakeWharton/butterknife
    //http://jakewharton.github.io/butterknife/
    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'
}

Activity中使用ButterKnife绑定View:

  • @BindView()
class ExampleActivity extends Activity {
  @BindView(R.id.title) TextView title;
  @BindView(R.id.subtitle) TextView subtitle;
  @BindView(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...
  }
}

Activity中使用ButterKnife绑定Resource:

  • @BindBool
  • @BindColor
  • @BindDimen
  • @BindDrawable
  • @BindInt
  • @BindString
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
  // ...
}

Fragment中使用ButterKnife绑定View:

  • @BindView()
public class FancyFragment extends Fragment {
  @BindView(R.id.button1) Button button1;
  @BindView(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;
  }
}

ViewHolder中使用ButterKnife绑定View:

  • @BindView()
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 {
    @BindView(R.id.title) TextView name;
    @BindView(R.id.job_title) TextView jobTitle;

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

其他注入方式

  • Bind arbitrary objects using an activity as the view root. If you use a pattern like MVC you can bind the controller using its activity withButterKnife.bind(this, activity).
  • Bind a view’s children into fields using ButterKnife.bind(this). If you use <merge> tags in a layout and inflate in a custom view constructor you can call this immediately after. Alternatively, custom view types inflated from XML can use it in the onFinishInflate() callback.

View Lists 注入:

  • @BindViews()

    @BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
    List<EditText> nameViews;
    
  • ButterKnife.apply()

    ButterKnife.apply(nameViews, DISABLE);
    ButterKnife.apply(nameViews, ENABLED, false);
    
  • Action()

    static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
      @Override public void apply(View view, int index) {
        view.setEnabled(false);
      }
    };
    
  • Setter()

    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);
      }
    };
    
  • ButterKnife.apply()

    //An Android Property can also be used with the apply method.
    ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
    

    Listener 注入:

  • @OnClick()

    @OnClick(R.id.submit)
    public void submit(View view) {
      // TODO submit data to server...
    }
    
    @OnClick(R.id.submit)
    public void submit() {
      // TODO submit data to server...
    }
    
    @OnClick(R.id.submit)
    public void sayHi(Button button) {
      button.setText("Hello!");
    }
    
    @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();
      }
    }
    

    Reset 注入:

  • unbinder.unbind()

    Fragments have a different view lifecycle than activities. When binding a fragment in onCreateView, set the views to null in onDestroyView. Butter Knife returns an Unbinder instance when you call bind to do this for you. Call its unbind method in the appropriate lifecycle callback.

    public class FancyFragment extends Fragment {
      @BindView(R.id.button1) Button button1;
      @BindView(R.id.button2) Button button2;
      private Unbinder unbinder;
    
      @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fancy_fragment, container, false);
        unbinder = ButterKnife.bind(this, view);
        // TODO Use fields...
        return view;
      }
    
      @Override public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
      }
    }
    

    其它注入方式

    By default, both @Bind and listener bindings are required. An exception will be thrown if the target view cannot be found.

    To suppress this behavior and create an optional binding, add a @Nullableannotation to fields or the @Optional annotation to methods.

    Note: Any annotation named @Nullable can be used for fields. It is encouraged to use the @Nullable annotation from Android’s “support-annotations” library.

    @Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;
    
    @Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
      // TODO ...
    }
    

    MULTI-METHOD LISTENERS

    Method annotations whose corresponding listener has multiple callbacks can be used to bind to any one of them. Each annotation has a default callback that it binds to. Specify an alternate using the callback parameter.

    @OnItemSelected(R.id.list_view)
    void onItemSelected(int position) {
      // TODO ...
    }
    
    @OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
    void onNothingSelected() {
      // TODO ...
    }
    

    BONUS

    Also included are findById methods which simplify code that still has to find views on a View, Activity, or Dialog. It uses generics to infer the return type and automatically performs the cast.

    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);