[Android/Kotlin] Toolbar(action bar)를 BaseActivity로 관리하기

유진·2023년 4월 2일

구현하고 싶은 것

  1. 각 액티비티의 타이틀명을 일괄 수정하기
  2. 뒤로가기 버튼 일괄 구현

-> BaseActivity를 상속함으로써 코드의 재활용성을 높임

이걸 하게 된.. 이유는... 딱히 필요성을 못 느낄 수도 있지만, 앱에 있어서, 특히! 마이페이지 같은 경우에는 해당 레이아웃(해당 화면 타이틀과 뒤로가기 버튼)이 계속 나오기 때문에 같은 레이아웃을 반복적으로 만들어 내는 내 자신이 너무 멍청하게 느껴져서 이다!

혼자 생각해보다가 ToolBar(action bar)를 BaseActivity에서 상속해서 쓴다면..? 이라는 생각을 계속 했던 것 같다...! 이렇게 쓰게 되면 상속 및 재사용을 하게 되어서 효율적인 코드가 되기 때문이다.

여기까지가 구현 배경 설명~

코드

BaseActivity.kt


open class BaseActivity : AppCompatActivity() {
    protected lateinit var customActionBar: Toolbar


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_base)

        customActionBar = findViewById(R.id.toolbar)
        setSupportActionBar(customActionBar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        //menuInflater.inflate(R.menu.menu_main, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            android.R.id.home -> {
                onBackPressed()
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }
}

SignupActivity.kt



        // MainActivity의 레이아웃을 frame_layout에 추가
        val inflater = LayoutInflater.from(this)
        inflater.inflate(R.layout.activity_signup, findViewById(R.id.frame_layout), true)

        supportActionBar?.title = "회원가입"

        //setContentView(R.layout.activity_signup)
        
        binding = ActivitySignupBinding.inflate(layoutInflater)

base_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <!-- 액션바 레이아웃 -->
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/white"
        android:elevation="4dp"
        android:contentInsetStart="0dp"
        android:contentInsetEnd="0dp"
        android:contentInsetLeft="0dp"
        android:contentInsetRight="0dp">


    <FrameLayout
        android:id="@+id/frame_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="?attr/actionBarSize"
        android:fitsSystemWindows="true" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

image

설명

  1. BaseActivity를 상속한다.
  2. MainActivity의 레이아웃을 frame_layout에 추가한다
    더 자세히 설명하자면, BaseActivity안에 있는 frame_layout 자리(노란 부분)에 기존에 있던 xxx_activity를 넣는 형식이다.
    ex. frame_layout에 sign_activity를 넣으면 된다.
  3. setcontentView를 사용하지 않는다.
    BaseActivity에 setContentView(R.layout.activity_base)가 있다. baseActivity를 상속해서 사용하기에 각각의 activity에서는 setContentView를 할 필요가 없다.
    ex. SignActivity를 담은 BaseActivity가 setcontentview를 통해 화면을 띄우기 때문에 문제 없다!
  4. 그러면 findviewbyid를 못한다 -> viewbinding으로 연결하면 된다.
  5. supportActionBar?.title = "회원가입" 을 통해 해당 activity에 쓸 타이틀 이름을 넣으면 된다! (빨간 부분)
    이를 통해 화면 안에 TextView를 이용해서 해당 화면의 타이틀을 표시하지 않아도 된다!

예상되는 문제점 및 해결책

  • 액션바가 필요하지 않은 activity가 있을 수 있다. -> BaseActivity를 상속 안하면 된다.
  • 디자인을 더 커스텀 하고 싶다. -> 상속을 받고, 오버라이드를 하면 됨
    ! .. 자세히 알아보겠음

참고 레퍼런스

chatGPT와의 기나긴 대화를 통해...

발생한 오류

현재 구조를 말로 설명하자면
BaseActivity에서 setcontentview를 한 상태이고, base_activity.xml에서 toolbar와 액티비티의 레이아웃을 담고 있는 frame_layout을 포함하고 있다.

그런데 xxxActivity에서 binding을 사용하여 클릭이벤트를 걸어둔게 잘 작동하지 않는다. 이를 findviewbyid로 바꾸니 작동 되긴하는데.. 무엇이 문제일까?

해결

BaseActivity를 open class에서 abstract(추상) 클래스로 바꾸고 아래 코드를 추가한다.

    abstract fun getLayoutResourceId(): Int

이를 상속하는 액티비티에서도 위 사항을 implement 해야한다.
xxxActivity.kt


        binding = ActivityMyReviewListBinding.inflate(layoutInflater)

        val inflater = LayoutInflater.from(this)
        inflater.inflate(R.layout.activity_my_review_list, findViewById(R.id.frame_layout), true)
        findViewById<FrameLayout>(R.id.frame_layout).addView(binding.root)
        supportActionBar?.title = "내가 쓴 리뷰"
        
        ...
        
    override fun getLayoutResourceId(): Int {
        return R.layout.activity_my_review_list
    }

사실 자세한 경위는 모르겠으나 레이아웃 아이디를 넘기고 findviewbyid를 통해 두번이나 레이아웃을 때려박아줘서인지, binding한 것들에서 클릭이벤트가 아주.. 잘 ..된다.. 이유를 알게된다면 추가하겠음!

profile
안드로이드... 좋아하세요?

0개의 댓글