(특히나 대단위 프로젝트에서 필수적이고) 앱은 한 프래그먼트에서 동작하지 않는 이상, 여러 액티비티를 이용하여 동작한다. 이 액티비티에 일일히 내비게이션을 만들수도 없는 일이니, ui를 하나만 만들고, 이를 뷰홀더로 addView 시켜 동작을 하도록 한다.
먼저 layout을 xml로 만든다.
- view_holder_navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:textSize="18sp"
/>
<ImageView
android:id="@+id/imageViewBack"
android:layout_width="25dp"
android:layout_height="25dp"
android:src="@drawable/ic_back"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="20dp"
/>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/black_4C4E56"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
다음, 내비게이션을 붙일 액티비티에, 먼저 상단에 내비게이션을 부착할 frameLayout을 생성한다.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".writing.WritingColorActivity">
<FrameLayout
android:id="@+id/frameLayoutNavigation"
android:layout_width="match_parent"
android:layout_height="50dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="15dp"
android:layout_marginTop="80dp"
android:layout_marginEnd="15dp"
android:layout_marginBottom="30dp"
android:orientation="vertical">
...
frameLayout의 id를 지정해줘야, 나중에 코틀린 파일에서 이를 찾아 뷰를 attach 시킨다. 필자는 레이아웃 성격과 id를 붙이는 타입이라, frameLayoutNavigation로 설정했다. 이 때, 뷰홀더에서 만든 레이아웃 height와 액티비티의 height를 동일하게 해야, 아래에 빈 공간 없이 ui상 예쁘게 착 붙는다.
다음, 내비게이션 뷰를 만들고, 내부에서 내비게이션 동작을 해줄 파일을 생성한다.
현재 가진 내비게이션은 back 이미지 하나만 있다. 여기에 클릭 리스너를 부여할 것이다.
- NavigationViewHolder.kt
package com.mary.kotlinprojectstudy.ui
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.ImageView
import com.mary.kotlinprojectstudy.R
class NavigationViewHolder @JvmOverloads constructor(
context: Context
){
interface NavigationViewHolderDelegate {
fun back()
}
lateinit var imageViewBack: ImageView
var navigationViewHolderDelegate : NavigationViewHolderDelegate? = null
var view: View = LayoutInflater.from(context).inflate(R.layout.view_holder_navigation, null)
init {
findView()
setListener()
}
private fun findView() {
imageViewBack = view.findViewById(R.id.imageViewBack)
}
private fun setListener() {
imageViewBack.setOnClickListener {
navigationViewHolderDelegate!!.back()
}
}
fun setTitle(title : String) {
textViewTitle.text = title
}
}
inflate를 이용하여 뷰를 확장할 것이다. 이 때, 확장할 부모 컨텍스트가 필요하다. 따라서, 뷰를 호출할 때 컨텍스트를 가져올 수 있도록 context 인자 하나를 받아온다.
동작은 인터페이스를 통해 가지고 온다. 이 때, 단순히 뷰를 붙인다고 해서 인터페이스를 바로 호출하는 것이 아니라, 인터페이스명을 호출해야 implement 되도록 할 것이다.
이게 무슨 소리인가는, 내비게이션을 붙이는 코드를 보면 이해할 수 있다.
- WritingColorActivity.kt
class WritingColorActivity : AppCompatActivity() {
...
lateinit var frameLayoutNavigation: FrameLayout
lateinit var navigationViewHolder: NavigationViewHolder
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_writing_color)
checkBundle()
findView()
initNavigation()
...
}
...
private fun findView() {
...
frameLayoutNavigation = findViewById(R.id.frameLayoutNavigation)
...
}
private fun initNavigation() {
navigationViewHolder = NavigationViewHolder(this)
navigationViewHolder.navigationViewHolderDelegate = object : NavigationViewHolder.NavigationViewHolderDelegate {
override fun back() {
onBackPressed()
}
}
navigationViewHolder.setTitle("Writing Color")
frameLayoutNavigation.addView(navigationViewHolder.view)
}
먼저 뷰를 붙일 frameLayout을 먼저 호출한다.
뷰를 붙일 내비게이션을 초기화한다. 이 때, 첫째줄에서 먼저 context 인자를 부여 + 다음 인터페이스명으로 인터페이스를 implement 하는 것이 보일 것이다(자바라면 new로 호출하면 된다..!).
이렇게 두면, 특히 대단위 프로젝트에서 내비게이션 버튼이 동일한 위치에 있어도 뷰홀더 쪽에서
public fun setImage 함수를 하나 만들고, 액티비티 쪽에서 호출하여 이미지 변경 -> 인터페이스를 호출하여 각각의 동작 부여
의 형태로 컨텍스트 쪽에서 자유롭게 뷰홀더를 제어할 수 있다.
물론... 인터페이스와 addView를 사용하면 결합도가 올라가는건 당연하지만.. 코드를 줄일 수 있다는 점에서 생각하면 좋은게 아닌가 싶고.. (곰곰)
결과물은 다음과 같이 두 액티비티에서 같은 디자인의 내비게이션을 공유하는 것을 볼 수 있다.
'Project > 안드로이드 프로젝트(RandomColorChart)' 카테고리의 다른 글
Android Studio, Kotiln] 7. 지정 텍스트 복사 (0) | 2021.02.18 |
---|---|
Android Studio, Kotlin] 6. (Open Source) Holo Color Picker (0) | 2021.02.17 |
Android Studio, Kotlin] 4. SwipeRefreshLayout, 스와이프 할 때마다 새로 갱신하는 레이아웃 (0) | 2021.02.08 |
Android Studio, Kotlin] 3. EditText의 정수값의 범위를 제한하는 방법 (0) | 2021.01.08 |
Android Studio, Kotlin] 2. addOnTextChangeListener. EditText가 변경될 때 마다 이벤트를 발생시키는 함수 (0) | 2021.01.08 |