안드로이드 네비게이션(Navigation)과 리사이클러뷰(RecyclerView)

 

 

* 이 글은 인프런 강의 <[왕초보편] 앱 8개를 만들면서 배우는 안드로이드 코틀린>을 보고 정리한 글입니다.

 


목표

 

네비게이션을 이용하여 가수를 선택하고

리사이클러뷰를 통해 각 가수의 노래 리스트들을 나타내자

 

 

 

1. 네비게이션(Navigation) 만들기

 

 

app 폴더에서 New > Android Resource File 클릭

 

 

리소스 타입을 네비게이션으로 설정하고 파일을 생성한다.

 

OK를 누른다

 

 

 

2. activity_main.xml에서 네비게이션 기능 넣기

 

NavHosFragment

 

1번에서 만든 네비게이션을 적용한다.

 

<androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentContainerView"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/trot_nav"
        tools:layout_editor_absoluteX="1dp"
        tools:layout_editor_absoluteY="1dp" />

 

android:layout_width="match_parent"
android:layout_height="match_parent"

레이아웃의 크기를 전체크기로 지정한다.

 

 

 

3. 프래그먼트(Fragment) 만들기

 

 

New > Fragment > Fragment(Blank)를 클릭한다.

 

 

Singer1Fragment, Singer2 Fragment , Singer3 Fragment를 생성한다.

 

 

 

4. 네비게이션에서 프래그먼트들 간의 연결 지정

 

 

네비게이션(trot_nav.xml)에서 프래그먼트들을 추가한다.

 

프래그먼트 연결

 

프래그먼트 간의 연결 지정

 

 

 

5. fragment_singer(1, 2, 3).xml

 

각 프래그먼트 xml 파일에서 앱 하단의 세 가수들의 버튼, 가수의 이름, 리사이클러뷰를 만든다.

 

<?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=".Singer1Fragment">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:gravity="center"
        android:text="영탁노래 리스트"
        android:background="@color/black"
        android:textColor="@color/white"
        android:textSize="30sp"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="10dp" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/singRV"
        android:layout_marginTop="70dp"
        android:layout_marginBottom="80dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        app:layout_constraintBottom_toBottomOf="parent">

        <ImageView
            android:id="@+id/image1"
            android:src="@drawable/photo1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:layout_weight="1" />

        <ImageView
            android:id="@+id/image2"
            android:src="@drawable/photo2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:layout_weight="1"/>

        <ImageView
            android:id="@+id/image3"
            android:src="@drawable/photo3"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:layout_weight="1"/>

    </LinearLayout>
    
</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

<androidx.constraintlayout.widget.ConstraintLayout

ConstraintLayout으로 설정한다.

 

app:layout_constraintBottom_toBottomOf="parent"

버튼을 맨 밑에 붙게 한다.

 

 

 

6. Singer(1, 2, 3) Fragment

 

버튼 클릭에 따라 프래그먼트를 바꾸도록 한다.

 

class Singer1Fragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View? {
        val view = inflater.inflate(R.layout.fragment_singer1, container, false)

        view.findViewById<ImageView>(R.id.image2).setOnClickListener {
            it.findNavController().navigate(R.id.action_singer1Fragment_to_singer2Fragment)
        }

        view.findViewById<ImageView>(R.id.image3).setOnClickListener {
            it.findNavController().navigate(R.id.action_singer1Fragment_to_singer3Fragment)
        }

        return view
    }
}

 

val view = inflater.inflate(R.layout.fragment_singer1, container, false)

view 변수에 fragment_singer1 레이아웃을 넣는다.

 

view.findViewById<ImageView>(R.id.image2).setOnClickListener {

fragment_singer1의 ImageView image2 부분이 클릭됐을 때

 

singr1에서 singer2 프래그먼트로 가는 id는 action_singer1Fragment_to_singer2Fragment 이다.

 

it.findNavController().navigate(R.id.action_singer1Fragment_to_singer2Fragment)

singer1Fragment에서 singer2Fragment로 이동한다. (네비게이션 사용)

 

 

 

7. rv_item.xml

 

리사이클러뷰에서 각 요소들이 어떻게 레이아웃 될지를 구성한다.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp">

    <TextView
        android:id="@+id/rvTextId"
        android:text="노래리스트"
        android:textSize="25sp"
        android:layout_margin="10dp"
        android:textStyle="bold"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

 

 

<LinearLayout

LinearLayout으로 변경

 

android:id="@+id/rvTextId"

TextView의 아이디 값을 rvTextId로 한다.

 

 

 

8. RVAdapter

 

리사이클러뷰의 어댑터를 만든다.

 

class RVAdapter (val items: MutableList<String>) : RecyclerView.Adapter<RVAdapter.ViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RVAdapter.ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.rv_item, parent, false)

        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: RVAdapter.ViewHolder, position: Int) {
        holder.bindItems(items[position])
    }

    override fun getItemCount(): Int {
        return items.size
    }

    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
        fun bindItems(item : String) {

            val rv_text = itemView.findViewById<TextView>(R.id.rvTextId)
            rv_text.text = item

        }
    }
}

 

inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView)

뷰홀더를 만들어준다.

 

val rv_text = itemView.findViewById<TextView>(R.id.rvTextId)

프래그먼트 파일에서의 뷰에 대하여 rvTextId를 변수로 갖는다.

 

rv_text.text = item

rv_text의 텍스트 값을 item들로 구성한다.

 

 

 

9. Singer(1, 2, 3) Fragment

 

노래목록들을 만들고(items), 데이터를 어댑터에 전달하여 그 반환값을 리사이클러뷰 레이아웃에 적용시킨다.

 

class Singer1Fragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val view = inflater.inflate(R.layout.fragment_singer1, container, false)

        val items = mutableListOf<String>()
        items.add("니가 왜 거기서 나와")
        items.add("이불")
        items.add("찐이야")
        items.add("비상")
        items.add("니가 왜 거기서 나와")
        items.add("이불")
        items.add("찐이야")
        items.add("비상")
        items.add("니가 왜 거기서 나와")
        items.add("이불")
        items.add("찐이야")
        items.add("비상")
        items.add("니가 왜 거기서 나와")
        items.add("이불")
        items.add("찐이야")
        items.add("비상")

        val rv = view.findViewById<RecyclerView>(R.id.singRV)
        val rvAdapter = RVAdapter(items)

        rv.adapter = rvAdapter
        rv.layoutManager = LinearLayoutManager(context)

        view.findViewById<ImageView>(R.id.image2).setOnClickListener {
            it.findNavController().navigate(R.id.action_singer1Fragment_to_singer2Fragment)
        }
        view.findViewById<ImageView>(R.id.image3).setOnClickListener {
            it.findNavController().navigate(R.id.action_singer1Fragment_to_singer3Fragment)
        }

        return view
    }
}

 

val items = mutableListOf<String>()

items.add("니가 왜 거기서 나와")

노래 데이터 값을 만든다.

 

val rv = view.findViewById<RecyclerView>(R.id.singRV)

뷰에서 리사이클러뷰를 찾아 rv라는 변수로 선언한다.

 

val rvAdapter = RVAdapter(items)

데이터들을 어댑터에 전달한다.

 

rv.adapter = rvAdapter

어댑터에서 반환한 값을 리사이클러뷰와 연결시킨다.

 

rv.layoutManager = LinearLayoutManager(context)

리사이클러뷰가 작동되도록 한다.