[Kotiln] 안드로이드 커스텀 액션바(toolbar) 완벽 가이드

2021. 11. 24. 16:06개발을 파헤치다/Android

반응형

안드로이드 커스텀 액션바

앱의 성공 요소를 따질 때 앱 디자인이 차지하는 요소가 굉장히 큽니다. 따라서 어지간한 서비스는 거의 대부분 커스텀 된 레이아웃을 사용하게 되는데요. 흔하게 사용되는 것이 오늘 알아볼 커스텀 액션바입니다. 이 액션바를 어떻게 내 마음대로 바꿀지, 그리고 메뉴 아이템까지 추가해서 특별한 기능을 넣는 방법까지 한 번에 알아봅니다. 해외 자료들 포함해서 4시간 동안이나 삽질한 내용을 단 10분 만에 가져가실 수 있으니 꼭 끝까지 읽어보시고 적용해보시길 바랍니다.

 

기존 Action Bar 제거하기

커스텀 액션바를 사용하기 위해 가장 먼저 해야 할 일은 기존 액션바를 사용하지 않도록 설정하는 것입니다.

res > themes.xml로 이동해서 아래와 같이 설정해 줍니다.


    <!-- Base application theme. -->
    <style name="Theme.Jejuand" parent="Theme.AppCompat.Light.NoActionBar"> -> 이 부분 수정
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/white</item>
        <item name="colorPrimaryVariant">@color/white</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
</resources>

sytle 태그의 parent를 Them.AppCompat.Light.NoActionBar로 설정해줍니다.
이렇게 설정해도 앱 제목이 액션바에 나타나게되는데요. 이 부분은 후에 액티비티에서 보이지 않게 설정하도록 합니다.

커스텀 Toolbar 생성하기

이제 기존 액션바 자리에 보여줄 커스텀 툴바를 만들어야겠죠
res > layout에 xml 파일을 생성합니다.

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    >
<androidx.appcompat.widget.Toolbar
    android:id="@+id/main_tool_bar"
     android:layout_height="@dimen/custom_tool_bar_height"
    android:layout_width="match_parent"
    android:background="@color/white">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_height="match_parent"
        android:layout_width="match_parent">

        <ImageView
            android:id="@+id/main_tool_bar_nav"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:srcCompat="@drawable/nav_icon"
            android:layout_marginTop="32dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0"/>


        <ImageView
            android:id="@+id/main_tool_bar_logo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:srcCompat="@drawable/main_logo_icon"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.6"/>

    </androidx.constraintlayout.widget.ConstraintLayout>




</androidx.appcompat.widget.Toolbar>
</layout>

위처럼 액션바 자리에 나타낼 메뉴를 직접 XML로 구현하면 됩니다. 저의 경우에는 로고와 내비게이션 아이콘을 넣었으며 Constraint Layout의 Horizontal bias를 통해 위치를 조정했습니다. 내비게이션 아이콘은 좌측 끝으로, 로고 이미지는 중간에 나오도록 적용했습니다. 
로고의 경우 후에 적용할 옵션 메뉴 아이콘들의 간격을 고려해서 bias를 0.6으로 설정했습니다.
이 부분은 직접 레이아웃 디자인을 확인해가면서 개발하는 것이 좋습니다.

Layout에 Toolbar 적용

이제 생성한 커스텀 툴바를 액티비티 레이아웃에 적용할 차례입니다. 툴바의 경우 재사용성이 높은 레이아웃이라 따로 xml 파일을 만들어 구현했는데요. 그럼 어떻게 액티비티의 레이아웃에 툴바를 적용할 수 있을까요?

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    >
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.leoncorp.jejuand.ui.main.MainActivity">

    <!-- Toolbar 레이아웃 적용 -->
    <include
        layout="@layout/main_tool_bar"
        />

    <!-- 메인 View Pager -->
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/main_view_pager"
        android:layout_height="0dp"
        android:layout_marginBottom="@dimen/layout_default_margin"
        android:layout_width="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/main_bottom_app_bar"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">
    </androidx.viewpager2.widget.ViewPager2>

이럴 때 사용하는 것이 include 태그입니다. 이 태그를 활용하면 layout 디렉토리에 정의된 다른 레이아웃을 그대로 불러올 수 있습니다. 이렇게 앞서 생성한 커스텀 툴바를 적용하면 됩니다.

커스텀 Option Menu 생성하기

보통 이렇게 액션바를 직접 적용하는 경우에는 특별한 기능을 추가하는 경우가 많습니다. 예를 들어, 액션바에 검색 아이콘을 넣어 검색 기능을 추가한다던지, 장바구니 기능을 넣는다던지 말이죠. 이번에는 커스텀 액션바에 메뉴를 추가해보도록 합니다.

먼저, res > menu 디렉토리를 생성하고 xml 파일을 생성합니다.


여기에 xml 파일을 생성하고 아래와 같이 메뉴 구현합니다

<?xml version="1.0" encoding="utf-8"?>

    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- 검색하기 메뉴 -->
    <item
        android:id="@+id/main_tool_bar_search"
        android:title="@string/main_tool_bar_search"
        app:showAsAction="ifRoom"
        app:actionLayout="@layout/custom_menu_search_icon">

    </item>

    <!-- 장바구니 메뉴 -->
    <item
        android:id="@+id/main_tool_bar_cart"
        android:title="@string/main_tool_bar_cart"
        app:actionLayout="@layout/custom_menu_cart_icon"
        app:showAsAction="ifRoom">

    </item>
</menu>

menu 태그에 item을 추가하는 방식으로 메뉴를 추가할 수 있습니다. 일반적으로 id, icon, title, showAsAction 속성만 추가하면 되는데 여기에는 actionLayout이라는 속성 값이 추가되어있습니다.
간단하게 설명을 하자면 액션바에서 메뉴 아이콘의 위치를 조정하기 위해 Item에 커스텀 레이아웃을 적용한 것이라고 할 수 있습니다. 많은 경우, 디자이너가 넘겨준 액션바 레이아웃을 보면 기본 적용된 메뉴 아이콘을 그대로 사용할 수 없는 경우가 많죠. 그렇기 때문에 메뉴 item도 커스텀이 필요합니다.

메뉴 아이템 커스텀을 위해 res > layout에 xml 파일을 추가합니다.

<?xml version="1.0" encoding="utf-8"?>
<!-- 메인 툴바 검색하기 아이콘 -->
<ImageView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/search_icon"
    android:paddingEnd="10dp"
    android:paddingStart="0dp"
    android:paddingTop="30dp"
    android:paddingBottom="10dp"
    />
    

그리고 위와 같이 ImageView를 통해 Icon을 적용하고 padding 값을 설정합니다. 그러면 커스텀 액션바에 나타날 때 간격 조정을 할 수 있습니다. 주의할 점은 이렇게 메뉴 Item에 actionLayout을 적용하게되면 아이템 클릭했을 때 아무런 반응이 없을 수 있는데요. 이 부분은 직접 클릭 이벤트를 적용해서 해결할 수 있습니다.

Activity에서 Toolbar와 Option Menu 적용

이제 앞서 생성한 툴바와 커스텀 옵션을 적용해줄 차례입니다.
먼저 툴바를 적용합니다. 액티비티의 onCreate 메서드에 적용하면 됩니다.

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        // Custom Tool bar 설정
        setCustomToolbar(R.id.main_tool_bar)

       
    }
    
     // 커스텀 툴바를 설정하는 메서드
    fun setCustomToolbar(layout: Int){
        val toolbar = findViewById<Toolbar>(layout)
        // 커스텀 툴바를 액션바로 설정
        setSupportActionBar(toolbar)
        val actionBar = supportActionBar
        // 액션바에서 앱 이름 보이지 않게 제거
        actionBar?.setDisplayShowTitleEnabled(false)
    }

이제 메뉴 옵션을 적용할 차례입니다. 커스텀 옵션 메뉴의 경우 onCreateOptionsMenu를 통해 레이아웃을 적용하게 되면 알아서 레이아웃이 적용되면서 툴바의 오른쪽에 아이콘이 추가가 됩니다. 그리고 클릭 시 어떤 기능을 수행할지는 onOptionsItemSelected 메서드에 구현하면 됩니다.

// MainActivity.kt

 /*
    *   메인 액션바 옵션을 설정하는 함수
    *
    * */
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        val inflater = menuInflater
        // res > menu에 생성한 xml 레이아웃을 적용
        inflater.inflate(R.menu.main_tool_bar_menu, menu)
        // 커스텀 메뉴에 대해서 클릭 이벤트를 설정한다
        val searchIcon = menu?.findItem(R.id.main_tool_bar_search)
        searchIcon?.actionView?.setOnClickListener {
            onOptionsItemSelected(searchIcon)
        }
        val cartIcon = menu?.findItem(R.id.main_tool_bar_cart)
        cartIcon?.actionView?.setOnClickListener {
            onOptionsItemSelected(cartIcon)
        }
        return super.onCreateOptionsMenu(menu)
    }
    
    // 커스텀 메뉴 아이콘 클릭시 루틴 실행
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            R.id.main_tool_bar_search -> {
                Toast.makeText(this, "검색하기", Toast.LENGTH_SHORT).show()
            }

            R.id.main_tool_bar_cart -> {
                Toast.makeText(this, "장바구니", Toast.LENGTH_SHORT).show()
            }
        }
        return super.onOptionsItemSelected(item)
    }

onCreateOptionsMenu에 보면 메뉴 아이템에 대해 클릭 이벤트를 적용하는 것을 볼 수 있습니다.
actionLayout을 사용해서 직접 클릭 이벤트를 적용해주는 것입니다. 이렇게하지않으면 클릭 시 아무런 반응이 없습니다. onOptionsItemSelected 함수가 아예 호출이 되지 않는 것이죠. actionLayout을 적용하지 않았다면 알아서 클릭 이벤트를 적용해주기 때문에 신경 쓸 필요가 없긴 합니다.
onOptionsItemSelected에서는 아이템의 ID 값에 따라 특정 루틴을 실행하도록 구현하면 됩니다.

적용해보시고 잘 안되시는 부분이 있다면 언제든지 댓글로 질문 주세요.

혹시 현재 개발자로 일하고 계시나요? 아니면 개발자로 취업을 앞두고 계신가요?

만약 그렇다면 제가 도움을 드릴 수 있을 것 같아서요. 취업과 커리어 컨설팅 서비스를 제가 직접 운영하고 있으니 한번 살펴보시면 도움이 될 것 같습니다. 아래 배너 클릭해서 확인해보세요.

반응형