Butter Knife 라이브러리 사용법
25 Mar 2017 | Android UX Open Source안드로이드 GUI 개발을 하다보면, 가장 귀찮은 것 중 하나가 화면에 컴포넌트를 하나 추가하는 것입니다.
예를 들어 화면에 버튼을 추가한다고 하면 다음과 같은 작업들을 거쳐야 합니다.
- XML Layout에 버튼을 추가한다.
- 해당 Activity(Fragment)에서 그 컴포넌트에 해당하는 변수를 추가한다. ex) private Button button;
- findViewById를 통해 그 컴포넌트를 변수에 할당한다. ex) button = (Button)findViewById(R.id.button)
- 그 버튼에 setOnClickListener를 통해 이벤트를 등록한다.
컴포넌트가 몇 개 안 될 경우는 큰 문제가 안되는데, 컴포넌트가 많아질수록 위 코드들은 감당이 안 될 정도로 많아지고 복잡해집니다. 이럴 때 ‘Butter Knife’ 라이브러리를 사용하면 코드량이 상당히 줄어듭니다. (사실, 이런 식으로 별거 아닌 코드를 Wrapping 하는 외부 라이브러리를 쓰는 걸 선호하진 않지만 Butter Knife는 생각보다 괜찮은 것 같아서 최근에 조금씩 사용을 해보고 있습니다.)
간단한 예제 코드로 알아보도록 하겠습니다. 더 자세한 내용은 공식 홈페이지를 참조하시면 됩니다. 버전에 따라 문법이 조금씩 바뀌고 있는데, 여기서는 현재 최신 버전인 8.5.1 기준으로 사용해보겠습니다.
gradle 세팅
dependencies { ... compile 'com.jakewharton:butterknife:8.5.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' ... }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:orientation="vertical" tools:context="com.snowdeer.butterknife.sample.MainActivity"> <TextView android:id="@+id/title" android:textStyle="bold" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Title" android:textSize="32sp" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Click Me!" /> <ImageView android:id="@+id/imageview" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
strings.xml
<resources> <string name="app_name">ButterKnifeSample</string> <string name="title">Hello. Butter Knife</string> </resources>
MainActivity.java
여기서 가장 중요한 부분은 onCreate() 함수 내의 다음 코드입니다.
ButterKnife.bind(this);
위 코드를 호출해주어야 각 View들이 바인딩(Binding)이 됩니다.
import android.graphics.drawable.Drawable; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.ImageView; import android.widget.TextView; import butterknife.BindDrawable; import butterknife.BindString; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class MainActivity extends AppCompatActivity { @BindView(R.id.title) TextView titleView; @BindView(R.id.imageview) ImageView imageView; @BindString(R.string.title) String title; @BindDrawable(R.mipmap.ic_launcher) Drawable drawable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); } @OnClick(R.id.button) void onButtonClicked() { titleView.setText(title); imageView.setImageDrawable(drawable); } ; }
Fragment 에서의 예제
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; } }
ListView 등에서 사용하는 Adapter 및 ViewHolder 예제
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); } } }
이벤트 등록 예제
@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(); } }