툴바를 구현하는 방법에 대한 고민.
툴바를 구현하는 데에는 아마도 일반적으로,
1. Toolbar widget을 사용하고, menu.xml파일을 구성하여 구현하는 방법
2. Layout view를 사용해서 구현하는 방법
이 2가지가 있을 수 있다.
본인은 안드로이드 개발을 처음 배울 때 2번의 방법으로 툴바를 구현하는 강의를 봤기 때문에 2번 방법만을 사용해 왔지만, 1번 방법과 어떤 차이 및 장단점이 있을까에 대해 알아보고 싶었는데, 찾아봐도 마땅한 이유를 찾기가 쉽지 않았다.
1번 방법은 아마 툴바 구현 방법 이라고 검색하면 가장 많이 나오는, 가장 일반적인 방법이라고 생각 되고,
2번 방법은 일반적인 layout을 마치 툴바'처럼' 구현하는 것이다.
그러면 이 중 어떤게 더 좋은 방법일까? 라고 묻는다면..
한번 다음과 같은 툴바를 구현해보자.
왼쪽과 오른쪽에 각각 버튼이 있고, 중앙에는 앱의 로고가 존재한다.
(백버튼이 될수도 있고, 햄버거 타입의 네비게이터 버튼이 될 수도 있겠다.)
이를 1번 방법으로 구현하려면,
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/toolbar_search"
android:icon="@drawable/ic_search"
android:title="Search"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/toolbar_notification"
android:icon="@drawable/ic_notification"
android:title="Notification"
app:showAsAction="always"/>
</menu>
위와 같은 xml 파일을 새로 만들어주고,
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_logo" />
</androidx.appcompat.widget.Toolbar>
툴바 레이아웃을 작성해주고,
override fun initViews() = with(binding) {
setSupportActionBar(toolBar)
supportActionBar.title = null
supportActionBar.setDisplayHomeAsUpEnabled(true)
supportActionBar.setDisplayShowHomeEnabled(true)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val menuInflater = menuInflater
menuInflater.inflate(R.menu.toolbar, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when(item.itemId) {
android.R.id.home -> finish() // BackButton
R.id.toolbar_search -> search()
R.id.toolbar_notification -> noti()
else -> Unit
}
return super.onOptionsItemSelected(item)
}
이런식으로 툴바 생성에 필요한 코드를 작성해줘야한다.
(이 방법 말고도 navigator를 이용해서 구현할 수도 있다.)
2번 방법으로 구현, ConstraintLayout을 사용한다면
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageButton
android:id="@+id/backButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_arrow_back_24"
android:background="@null"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="16dp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<ImageButton
android:id="@+id/searchButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_search"
android:background="@null"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@id/notificationButton"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="16dp"/>
<ImageButton
android:id="@+id/notificationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_notification"
android:background="@null"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="16dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
이처럼 layout xml에 필요한 위젯을 전부 넣고,
private fun initButton() = with(binding) {
searchButton.setOnClickListener {
}
backButton.setOnClickListener {
}
notificationButton.setOnClickListener {
}
}
이렇게 그냥 버튼 클릭 리스너를 달아주기만 하면 된다.
주니어(?)의 입장에서 각 방법에 대해 평가를 해보자면..
일단 2번 방법은 매우 친숙하다. 평소의 다른 view를 구성하는 방식과 다른게 전혀 없다보니 별다른 지식이 없어도 된다. 애초에 Appbar를 대체하려고 나온 Toolbar 자체가 하나의 view기 때문에 구조상의 문제도 없다. 코드의 길이조차 작다. 버튼 클릭 리스너를 when문으로 작성할수도 있을것이다.
단점을 생각해보면, 각 항목마다의 배치를 직접 정해주어야 한다는것. 즉 margin값등을 전부 수동으로 입력해 줘야 한다. (일반적인 가이드라인(material)의 규격을 벗어날 수도 있다)
그러나 당연하게도 1번 방법이 아마 코드상으로도, 디자인적으로도 표준에 적합한 방법일것이다. material design의 가이드라인에 따라 만들어진 방법이니까. 또한 구조가 거의 비슷한 material toolbar를 이용하면 좀 더 다양한 동작을 수행할 수 있는 toolbar를 훨씬 쉽게 구현할 수도 있다. (기본 코드가 기본 툴바 위젯 사용법과 동일하다)
(https://material.io/components/app-bars-top#usage)
개인적으로 아쉬운점은 레이아웃 xml 파일에서 각 위젯들이 한번에 안보인다는 점이다. 즉 레이아웃 xml만 봣을 때, 이 툴바가 어떻게 생겼는지 한눈에 파악하기 어렵다. 따로 커스텀하게 넣은 이미지뷰는 하위뷰에 있으며, 메뉴는 따로 메뉴 xml을 만들었고, navigator는 또 별도로 존재한다. 툴바도 결국 그저 하나의 뷰인데 뷰를 구성하는 요소들이 너무 곳곳에 퍼져있는 느낌이다.
결론.
결국 편한것을 쓰는게 제일 베스트인가?
그럼에도 모든 경우에 1번이 가장 좋은것은 아니겠지만, 1번 방법이 가지는 큰 장점이라면, 어쨋든 개발은 혼자하는것이 아니므로 규격을 따르는건 매우 중요한 점이라는 것이다.
물론 아주 간단하게 툴바를 구성해도 되는 작은 프로젝트라면, 규모에 따라 혹은 편의에 따라 2번 방법처럼 사용해도 크게 문제는 없어보인다.
그러나 툴바에 기능이 붙을수록 ( ex)collapsing toolbar등 ) 이걸 레이아웃 뷰로 구현하는건 경우에 따라 더 힘들수도 있다. 또한 하나의 프로젝트 내에서 간단하다는 이유로 어떤 뷰는 그냥 레이아웃으로 만들어버리고, 어떤 뷰는 툴바 위젯을 사용해서 만드는건 좋은 방법이 아닐것이다. (뷰마다 툴바의 디자인도 달라질 가능성이 존재한다. margin 값이라던지.. )
아직 공부만 하는 학생이다보니 실제로 현업에서는 어떤식으로 주로 사용하는지, 아니면 크게 여의치 않는 부분인지도 궁금하다.
'Android > Tips' 카테고리의 다른 글
startActivityForResult Deprecated (0) | 2022.02.18 |
---|---|
CompileSdk, TargetSdk, MinSdkVersion 비교 (0) | 2021.12.16 |
RecyclerView에 animation 효과 주기 (0) | 2021.12.04 |
Recyclerview adapter 재활용하기 (0) | 2021.11.15 |
TabLayout (0) | 2021.11.15 |