안드로이드 커스텀 뷰를 만드는 방법에 대해 알아보자. 위와 같이 3개의 별을 만들고 "눌러서 갱신" 버튼을 누르면 다음 별이 선택되 노란색 별로 바뀌는 것을 구현해 볼 것이다.
1. 커스텀 뷰의 레이아웃을 결정한다.
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:id="@+id/star1"
android:src="@drawable/star"
android:layout_margin="4dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/star2"
android:src="@drawable/star_empty"
android:layout_margin="4dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/star3"
android:src="@drawable/star_empty"
android:layout_margin="4dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</merge>
커스텀 뷰의 레이아웃은 위와 같다. @drawable/star 은 노란색으로 칠해진 별 이미지이고 @drawable/star_empty 는 테두리만 있는 별 이미지다. 위 코드에서 루트 태그가 LinearLayout이 아니라 merge태그를 사용했다. 커스텀 뷰가 LinearLayout을 상속할 예정이므로 LinearLayout의 중첩을 피하기 위해서 merge 태그를 사용했다.
2. 레이아웃 XML로 설정할 수 있는 항목을 attrs.xml에 작성한다.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
<attr name="selected" format="integer" />
</declare-styleable>
</resources>
커스텀 뷰의 xml로 설정을 변경할 수 있게 attrs.xml에 위와 같이 작성했다. xml 또는 AttributeSet 클래스로 interger 타입의 selected 변수를 접근할 수 있다. 이에 대해서 차차 알아볼 예정이다.
3. 커스텀 뷰의 클래스를 작성한다.
public class MyCustomView extends LinearLayout {
private ImageView mStar1;
private ImageView mStar2;
private ImageView mStar3;
private int mSelected = 0;
public MyCustomView(Context context) {
super(context);
initializeViews(context, null);
}
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
initializeViews(context, attrs);
}
public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initializeViews(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initializeViews(context, attrs);
}
/**
* 레이아웃 초기화
*
* @param context
*/
private void initializeViews(Context context, AttributeSet attrs) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.three_stars_indicator, this);
if (attrs != null) {
//attrs.xml에 정의한 스타일을 가져온다
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView);
mSelected = a.getInteger(0, 0);
a.recycle(); // 이용이 끝났으면 recycle() 호출
}
}
@Override // inflate가 완료되는 시점에 호출된다.
protected void onFinishInflate() {
super.onFinishInflate();
mStar1 = (ImageView) findViewById(R.id.star1);
mStar2 = (ImageView) findViewById(R.id.star2);
mStar3 = (ImageView) findViewById(R.id.star3);
// 처음에만 xml로부터의 지정을 반영시키고자 두 번째 인수인 force를 true로 한다
setSelected(mSelected, true);
}
/**
* 지정된 번호로 선택한다
*
* @param select 지정할 번호(0이 가장 왼쪽)
*/
public void setSelected(int select) {
setSelected(select, false);
}
private void setSelected(int select, boolean force) {
if (force || mSelected != select) {
if (2 > mSelected && mSelected < 0) {
return;
}
mSelected = select;
if (mSelected == 0) {
mStar1.setImageResource(R.drawable.star);
mStar2.setImageResource(R.drawable.star_empty);
mStar3.setImageResource(R.drawable.star_empty);
} else if (mSelected == 1) {
mStar1.setImageResource(R.drawable.star_empty);
mStar2.setImageResource(R.drawable.star);
mStar3.setImageResource(R.drawable.star_empty);
} else if (mSelected == 2) {
mStar1.setImageResource(R.drawable.star_empty);
mStar2.setImageResource(R.drawable.star_empty);
mStar3.setImageResource(R.drawable.star);
}
}
}
public int getSelected() {
return mSelected;
}
}
4. 메인 앱의 레이아웃에 삽입한다.
<com.advanced_android.compositecustomviewsample.MyCustomView
android:id="@+id/indicator"
app:selected="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
app 이름 공간에 접근하기 위해서는 xmlns:app="http://schemas.android.com/apk/res-auto"를 넣어야 된다. 그러면 이 이름공간을 통해 자동으로 attrs.xml에서 정의한 내용에 접근할 수 있다.
5. 메인 액티비티에서 커스텀 뷰를 컨트롤 한다.
final MyCustomView indicator = (MyCustomView) findViewById(R.id.indicator);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int selected = indicator.getSelected();
if (selected == 2) {
selected = 0;
} else {
selected++;
}
Log.d("MainActivity", "selected=" + selected);
indicator.setSelected(selected);
}
});
'안드로이드 > 기본' 카테고리의 다른 글
예제를 통해 안드로이드 데이터 바인딩에 대해 알아보자 (1) | 2017.08.05 |
---|---|
SQLite 주의할 점 및 팁 - DB LOCK(락), SQLiteOpenHelper (2) | 2017.08.05 |
마커(Marker) 인터페이스, 어노테이션(Annotation) 활용 (0) | 2017.08.03 |
안드로이드 태스크, launchMode, Intent 플래그 총정리 (0) | 2017.08.03 |
안드로이드 슬립 상태 대처하기 (0) | 2017.08.02 |