햄버거 버튼 동작이벤트를 넣어보자.
1. GNB UI 생성
MainActivity 로 이어질 Home
별도 Activity 로 이어질 버튼을 넣어보겠다
<?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">
<LinearLayout
android:id="@+id/ll_menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="0dp"
android:layout_marginLeft="0dp"
android:orientation="vertical"
android:background="@color/white">
<LinearLayout
android:id="@+id/ll_item_1"
android:layout_width="match_parent"
android:layout_height="53dp"
android:gravity="center_vertical"
android:paddingLeft="40dp"
android:paddingRight="20dp"
android:layout_marginBottom="4dp"
android:background="@color/home_menu_bg_light_gray"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_item_1"
android:layout_width="wrap_content"
android:layout_height="53dp"
android:layout_gravity="center_vertical"
android:paddingLeft="0dp"
android:gravity="center_vertical"
android:text="Home"
android:textSize="@dimen/sp_17"
android:maxLines="1"
android:textColor="@color/orange"
android:textStyle="bold" />
<View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
</View>
<ImageView
android:id="@+id/iv_orange_arrow1"
android:layout_width="7dp"
android:layout_height="12dp"
android:layout_marginRight="0dp"
android:background="@drawable/btn_detail_org"/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_item_2"
android:layout_width="match_parent"
android:layout_height="53dp"
android:gravity="center_vertical"
android:paddingLeft="40dp"
android:paddingRight="20dp"
android:layout_marginBottom="4dp"
android:background="@color/home_menu_bg_light_gray"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_item_2"
android:layout_width="wrap_content"
android:layout_height="53dp"
android:layout_gravity="center_vertical"
android:paddingLeft="0dp"
android:gravity="center_vertical"
android:text="기본 Recycler View"
android:textSize="@dimen/sp_17"
android:maxLines="1"
android:textColor="@color/orange"
android:textStyle="bold" />
<View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
</View>
<ImageView
android:id="@+id/iv_orange_arrow2"
android:layout_width="7dp"
android:layout_height="12dp"
android:layout_marginRight="0dp"
android:background="@drawable/btn_detail_org"/>
</LinearLayout>
</LinearLayout>
</layout>
나는 이런식으로 추가해봤다.
메뉴가 몇개안되기때문에 LinearLayout을 사용했음!!
2. MainActivity 에 GNB 영역 추가
다른 액티비티에서는 사용하지않고 Main 에 들어왔을때만 보이면 되기때문에 MainActivity 에만 추가하자
<com.example.basic_mobile.ui.TitleBar
android:id="@+id/inc_titlebar"
android:layout_width="match_parent"
android:layout_height="@dimen/title_height"
app:layout_constraintTop_toTopOf="parent"/>
////추가////
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="MissingConstraints">
<com.example.basic_mobile.ui.CustomDrawerMenu
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.google.android.material.navigation.NavigationView>
그런데!! 이렇게하면 햄버거버튼 위에 위치하며 버튼이랑 겹쳐진다
각 요소들을 나열해놓기만 하고 줄을 제대로 세우지 않았기때문에 이런식으로 먹혀버린다...
LinearLayout 으로 서열을 제대로 알려주자
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.basic_mobile.ui.TitleBar
android:id="@+id/inc_titlebar"
android:layout_width="match_parent"
android:layout_height="@dimen/title_height" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:orientation="vertical"
android:visibility="gone">
<com.example.basic_mobile.ui.CustomDrawerMenu
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.google.android.material.navigation.NavigationView>
<Button
android:id="@+id/btn_recycler"
android:text="기본 Recycler View"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_epoxy"
android:text="epoxy View"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/btn_recycler"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
이런식으로 ConstraintLayout -> LinearLayout -> 요소 배치 의 방식으로 설정하면 된다.
자 이제 보여줄 화면을 세팅해놨다면, 햄버거버튼 클릭시에만 NavigationView 가 visible 되도록 해보자
3. GNB 클릭 이벤트 설정
MainActivity 에서 햄버거버튼을 클릭했을때,
메뉴영역이 노출되어있으면 visibility = gone, 미노출되어있으면 visible 상태로 만들어보자.
하지만 햄버거버튼, 뒤로가기, 타이틀 로고 이미지클릭시 실행되는 동작들이 Activity 별로 달라야할때가 있다.
즉 include 된 페이지의 이벤트를 부모 페이지에게 알려줘야할때 쓰는 방법을 사용해보겠다
1) TitleBar 상수 추가
Title bar 에서 어떤 동작을 수행했는지 알려주기 위해서 상수를 추가했다
class TitleBar : FrameLayout {
companion object {
const val BUTTON_NAME_BACK = 1 //뒤로가기
const val BUTTON_NAME_HOME_MENU = 2 //햄버거버튼
const val BUTTON_NAME_HOME = 3 //타이틀
}
...
}
뒤로가기, 햄버거버튼, 타이틀을 클릭했을때 각 상수값을 부모 페이지로 보내도록 하겠다
class TitleBar : FrameLayout {
object {
const val BUTTON_NAME_BACK = 1
const val BUTTON_NAME_HOME_MENU = 2
const val BUTTON_NAME_HOME = 3
const val BUTTON_NAME_CLOSE = 4
}
...
private fun initView() {
//햄버거버튼 클릭 이벤트
binding?.ivMenu?.setOnClickListener() {
///이곳에서 상수값을 보내고 싶음
}
}
...
}
자 어떻게 보내야할까?
내가 택한 방법으로는 DataChangeListener를 이용하는것이다.
리스너를 하나 만들고 부모에서 해당리스너를 오버라이딩 시켜서 사용하는 방법이다. 차근차근 해보자
2) DataChangeListener 추가
TitleBar 하단에 interface로 리스너를 하나 만들어준다.
그리고 그 안에 메소드를 하나 추가해서 파라미터로 상수값을 제공받는다
class TitleBar : FrameLayout {
object {
const val BUTTON_NAME_BACK = 1
const val BUTTON_NAME_HOME_MENU = 2
const val BUTTON_NAME_HOME = 3
const val BUTTON_NAME_CLOSE = 4
}
...
private var binding: IncTitlebarBinding? = null
private var dataChangeListener: DataChangeListener? = null
private fun initView() {
//햄버거버튼 클릭 이벤트
binding?.ivMenu?.setOnClickListener() {
if(dataChangeListener != null)
this.dataChangeListener?.onChanged(BUTTON_NAME_HOME_MENU,"")
}
}
...
interface DataChangeListener {
fun onChanged(index: Int, value : String);
}
}
햄버거버튼을 클릭했을 때, 해당 리스너의 onChanged 메소드로 상수값을 전달한다
그렇다면 이것을 부모가 쓰게끔 컨트롤가능한 메소드를 하나 추가해준다
3) 부모페이지 전용 메소드 추가
class TitleBar : FrameLayout {
object {
const val BUTTON_NAME_BACK = 1
const val BUTTON_NAME_HOME_MENU = 2
const val BUTTON_NAME_HOME = 3
const val BUTTON_NAME_CLOSE = 4
}
...
private var binding: IncTitlebarBinding? = null
private var dataChangeListener: DataChangeListener? = null
private fun initView() {
//햄버거버튼 클릭 이벤트
binding?.ivMenu?.setOnClickListener() {
if(dataChangeListener != null)
this.dataChangeListener?.onChanged(BUTTON_NAME_HOME_MENU,"")
}
}
...
//부모 사용 전용 메소드
fun setOnClickBackBtnListener(listener: (Int, String) -> Unit) {
this.dataChangeListener = object : DataChangeListener {
override fun onChanged(index: Int, value: String) {
listener(index, value)
}
}
}
interface DataChangeListener {
fun onChanged(index: Int, value : String);
}
}
이렇게 메소드를 만들어서 뚫어줘야 부모에서 사욯할 수 있다.
전체 코드는 이렇다
class TitleBar : FrameLayout {
companion object {
const val BUTTON_NAME_BACK = 1
const val BUTTON_NAME_HOME_RIGHT_SIDE = 2
const val BUTTON_NAME_HOME = 3
const val BUTTON_NAME_CLOSE = 4
}
constructor(context: Context) : super(context) {
inflateView()
initView()
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
inflateView()
initView()
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
inflateView()
initView()
}
private var binding: IncTitlebarBinding? = null
private var dataChangeListener: DataChangeListener? = null
private fun inflateView() {
binding = IncTitlebarBinding.inflate(LayoutInflater.from(context))
addView(binding?.root)
}
private fun initView() {
//클릭이벤트
binding?.ivMenu?.setOnClickListener() {
if(dataChangeListener != null)
this.dataChangeListener?.onChanged(BUTTON_NAME_HOME_RIGHT_SIDE,"")
}
}
/**
* set title (TEXT)
*/
fun setTitle(title:String) {
if (title.isNullOrEmpty()) {
binding?.tvTitle?.hide()
} else {
binding?.tvTitle?.show()
binding?.tvTitle?.text = title
}
}
fun showMenuIcon(b: Boolean) {
if (b) {
binding?.ivMenu?.show()
} else {
binding?.ivMenu?.hide()
}
}
fun setOnClickBackBtnListener(listener: (Int, String) -> Unit) {
this.dataChangeListener = object : DataChangeListener {
override fun onChanged(index: Int, value: String) {
listener(index, value)
}
}
}
interface DataChangeListener {
fun onChanged(index: Int, value : String);
}
}
4. Main Activity 에서 리스너 사용
setTitleBar 부분에서 아래와같이 해당 메소드를 이용할 수 있다
class MainActivity : AppCompatActivity() {
private var binding: ActivityMainBinding? = null
lateinit var drawerLayout: DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding!!.root)
setTitleBar()
}
private fun setTitleBar () {
binding?.incTitlebar?.setTitle("MAIN")
binding?.incTitlebar?.showMenuIcon(true)
binding?.incTitlebar?.setOnClickBackBtnListener { i, s ->
when (i) {
TitleBar.BUTTON_NAME_HOME -> {} //로고 클릭 event
TitleBar.BUTTON_NAME_BACK -> {} //뒤로가기 event
TitleBar.BUTTON_NAME_HOME_MENU -> { //햄버거버튼 event
if (binding?.navView?.isVisible == true) {
binding?.navView?.hide()
} else {
binding?.navView?.show()
}
}
}
}
}
}
뭐 모든 페이지가 같은 동작을 수행한다면 굳이 이럴필요는 없지만
아닌경우가 많기때문에.. 해당방법을 사용했다.
중심적으로 봐야할점은 부모로 이벤트를 보내는 방법!! 나중에 fragment 에서 리스트클릭하거나 다양한 이벤트를 보낼때 이러한 방식을 사용하게된다.
완성본!
'Mobile > Android' 카테고리의 다른 글
Kotlin - Android Hilt 사용하여 앱 개발하기 (2) - Network 통신 (0) | 2024.03.28 |
---|---|
Kotlin - Android Hilt 사용하여 앱 개발하기 (1) - Hilt 추가 (0) | 2024.03.28 |
Kotlin - Android 앱 개발하기 (4) - 타이틀 바 추가 (0) | 2024.03.05 |
Kotlin - Android 앱 개발하기 (3) - splash 추가 (0) | 2024.02.26 |
Kotlin - Android 앱 개발하기 (2) - 페이지 이동, binding 사용 (0) | 2024.02.24 |