시간표와 같이 일정 패턴으로 반복된 뷰들을 많이 사용해야하고 그로 인해 코드가 길어지고 복잡해 진다면 커스텀 뷰를 고려해보는게 좋습니다.
커스텀뷰 사용이 불편하시다면 Recyclerview를 이용하는 것도 방법입니다. ( 보여줘야할 뷰들의 갯수가 불규칙적일 경우 recyclerview가 더 적합할 것 같습니다. )
>> 작업이 필요한 View의 형태
개발중인 달력뷰에 사용중인 투두 리스트의 리스트로 체크 박스를 클릭하면 각 체크 박스에 맞는 이미지가 채워지고 텍스트에 줄이 생기도록 개발해야 합니다. Recyclerview만으로도 개발은 가능하지만 다른 화면에서 재사용할 예정이라 커스텀뷰를 활용 했습니다.
나아가 attrs를 활용해 xml 생성시 주어진 옵션으로 각 색과 이미지가 셋팅 되도록 했습니다.
>> 기존 xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:id="@+id/ctContent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/ivUncheck"
android:layout_width="15dp"
android:alpha="0"
android:layout_height="15dp"
android:src="@drawable/ic_calendar_todo_water_uncheck"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/ivCheck"
android:alpha="1"
android:layout_width="15dp"
android:src="@drawable/ic_calendar_todo_water"
android:layout_height="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.wony.plantdiary.view.custom.PTextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="물주기"
android:textColor="@color/color_57bcff"
android:textSize="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/ivCheck"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/viewMiddleLine"
android:scaleX="0"
android:layout_width="0dp"
android:layout_height="2dp"
android:background="@color/color_57bcff"
app:layout_constraintBottom_toBottomOf="@+id/tvTitle"
app:layout_constraintLeft_toLeftOf="@+id/tvTitle"
app:layout_constraintRight_toRightOf="@+id/tvTitle"
app:layout_constraintTop_toTopOf="@+id/tvTitle" />
</androidx.constraintlayout.widget.ConstraintLayout>
이미 'PTextView' 커스텀 뷰를 생성해서 사용중이고, 해당 뷰는 추후 발생할 수 있는 폰트 변경과 같이 모든 텍스트뷰에 변경되는 적용사항을 한번에 하기 위함입니다.
그리고 위의 xml이 많이 복잡하진 않지만 반복해서 2~3번 사용하고 다른 뷰들도 많이 있는 xml이라면 많이 복잡하게 느껴질 수 있습니다.
PTodoView.Kt
open class PTodoView @JvmOverloads constructor(context: Context, var attrs: AttributeSet?) :
ConstraintLayout(context, attrs) {
private var binding: ViewTodoBinding = DataBindingUtil.inflate(
LayoutInflater.from(context), R.layout.view_todo, this, true
)
private val typedArray = context.obtainStyledAttributes(attrs, R.styleable.PTodoView)
var type = typedArray.getInt(R.styleable.PTodoView_type, TodoData.TYPE_WATER)
init {
initCheckOff()
initType()
initClick()
}
....
}
커스텀 뷰는 xml과 함께 class파일을 생성해야 합니다. class파일 생성은 필수는 아니지만 클릭 이벤트라던지, 애니메이션등 코드로 구현해야할 부분이 있다면 필수로 생성해주셔야 합니다.
JvmOverloads
자바 코드를 사용해서 커스텀 뷰를 만든다면 여러 생성자를 선언해야 하는데 JvmOverloads 어노테이션을 사용하면 코드가 훨씬 간결해진다. ( 자세한 내용은 추가 포스팅을 작성하도록 하겠습니다. )
>> Attribute로 옵션 주기
xml에 Textview를 생성할때 텍스트의 크기와 색깔을 지정해주는 것과 같이 커스텀 뷰를 xml에 생성할때 옵션을 지정하도록 할 수 있습니다. 코드로 옵션을 부여할 수 있지만 안드로이드 코딩 패턴들이 그렇듯 뷰는 xml에서 최대한 설정하도록 권고합니다.
attrs.xml에 옵션 선언
처음 커스텀 뷰를 생성하신다면 attrs 파일이 없어 생성하셔야 합니다. ( res > values )
<declare-styleable name="PTodoView">
<attr name="type" format="integer"/>
</declare-styleable>
생성된 파일에 'PTodoView' 라는 이름으로 type이라는 속성을 Integer 형태로 선언했습니다. 여기서 이름은 커스텀뷰의 이름으로 지정해 구분하기 용이하도록 했습니다.
실제 사용하기
<com.wony.plantdiary.view.custom.PTodoView
android:id="@+id/todoWater"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
app:type="1" />
실제 activity xml에 커스텀 뷰를 추가한 모습입니다. 'app:type' 으로 1이란 속성을 지정했습니다. 아래 예시와 같이 type을 넘겨 받아서 사용합니다. 전체 코드는 위 커스텀뷰 클래스 코드를 참고해주세요.
...
private val typedArray = context.obtainStyledAttributes(attrs, R.styleable.PTodoView)
var type = typedArray.getInt(R.styleable.PTodoView_type, TodoData.TYPE_WATER)
....
위처럼 커스텀 뷰를 활용한 경우 저는 200줄이 넘는 xml을 13줄 정도로 줄일 수 있었습니다. 실제로 앱의 용량이나 그런 부분에는 미비할 수 있지만 앱이 커질 수록 이런 미비한 부분들이 쌓여 크게 다가올수 있습니다. ( 유지보수 관점으로도 그렇습니다. )
'안드로이드 > 코틀린' 카테고리의 다른 글
Webview 파일 다운로드 구현하기 (1) | 2021.06.10 |
---|---|
Webview 이미지 업로드 구현하기 ( 카메라, 갤러리 ) (7) | 2021.05.27 |
[안드로이드/Kotlin] WorkManager를 활용한 백그라운드 작업 (0) | 2021.02.16 |
[Android/Kotlin] Transformations를 사용해 Livedata 활용하기 (0) | 2021.02.10 |
[Android/Kotlin] Room 마이그레이션 (0) | 2021.01.27 |