5주차 3일 TapLayout과 Viewpager2,RecyclearView
1.TapLayOut&ViewPager2
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android" //중요! 이 부분이 꼭 필요
android:id="@+id/viewPage2"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tabLayout"/>
TapLayout의 구성은 이러한데, 여기서 주의해야할 것은 TabItem 속 text는 진짜 그려지는게 아니라 레이아웃 구성상 보기 편하도록 나오는 것이다.
재밌는 것은 adapter에서 size를 주면 아이템 선언은 내가 구성한 레이아웃 상에서는 필요 없다는 것이다.
fragment나 activicy에서 따로 속성을 지정해줄 수 있기 때문인데, 이러한 상황이 아니라면 item을 줘서 제어가 가능하다.
해당 TapLayout과 ViewPager2는
각 탭의 Fragment를 생성한 뒤 연결되었는데,
package com.example.class1
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [TodoFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class TodoFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_todo, container, false)
val recyclerView = rootView.findViewById<RecyclerView>(R.id.todo_recyclear)
var todoList = arrayListOf<Todoitem>()
for(i in 1 .. 100) {
todoList.add(Todoitem("todo ${i}"))
}
val todoAdapter=TodoAdapter(todoList)
recyclerView.adapter = todoAdapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
return rootView
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment Viewpager2Fragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
TodoFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
해당 Fragment가 Todo탭의 fragment다.
onCreate | Fragment가 생성될 때 마다 호출. 초기화 인자를 가져옴 |
onCreateView() | Fragment에서 레이아웃 인플레이트를 하고 UI구성요소를 설정함 |
newInstance() | 지정 매개 변수로 Fragment의 새 인스터를 생성하는 보조 메서드. 인자를 전달하는게 일반적인 형태 |
여기서 주의해야할 점은 OnCreateView는 Activity.kt와 다른 역활을 한다는거다.
비슷한 역활을 하나 생명 주기가 다른데, OnCreateView는 fragment의 생명 주기를 따른다.
또한 OnCreateView는 View 인스턴스를 반환해야하며, 이 반환한 View는 Fragment의 UI를 구성하는데 사용된다.
class FragmentAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {
override fun getItemCount(): Int {
return 2
}
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> TodoFragment()
else -> BookMarkFragment()
}
}
}
이 Adapter는 위에 생성된 framgent 두 개와 ViewPager2를 연결하는 adpter다.
getItemCount() | 표시할 fragment의 수를 반환 |
createFragment() | 지정 위치의 fragment를 생성하고 반환 |
package com.example.class1
import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
class MainActivity : AppCompatActivity() {
@SuppressLint("MissingInflatedId")
val title = listOf("Todo","Bookmark")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewPageer2:ViewPager2 = findViewById(R.id.viewPage2)
val tapLayout: TabLayout = findViewById(R.id.tabLayout)
val adapter = FragmentAdapter(this)
viewPageer2.adapter = adapter
TabLayoutMediator(tapLayout, viewPageer2){ tab,position->
tab.text = title[position]
}.attach()
}
}
이렇게 만들어준 adapter를 이용하여 MainActivity에서 해당 기능을 연결해준다.
먼저 viewpager2와 taplayout을 호출한 뒤 viewpager.adapter를 FragmentAdapter와 연결해준다.
이후 TapLayoutMediator를 이용하여 위에 저장된 리스트에서 타이틀 이름을 가져와 그려준다.
이 방식은 튜터님께 질의하여 앞으로 다른 사람과 협업할 때 어느 모습이 더 편한가에 대해서 질문하여 나온 형태다.
2. TapLayout & ViewPager2 & RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TodoFragment">
<!-- TODO: Update blank fragment layout -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/todo_recyclear"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
해당 Fragment는 Todo의 Fragment를 구성한 요소로, recyclerview를 가진다.
그리고 recycleview는 데이터를 받아올 아이템이 필요한데 이는
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/texttodo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="todo"
android:textSize="20dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"/>
</LinearLayout>
해당 item_todo 레이아웃이다.
그렇다면 이제 남은 것은 리사이클 뷰와 프레그먼트를 연결하는 것이다.
package com.example.class1
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import org.w3c.dom.Text
class TodoAdapter(val todoList: ArrayList<Todoitem>) :
RecyclerView.Adapter<TodoAdapter.TodoHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoAdapter.TodoHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_todo, parent, false)
return TodoHolder(view)
}
override fun onBindViewHolder(holder: TodoAdapter.TodoHolder, position: Int) {
holder.todo.text = todoList[position].todo
}
override fun getItemCount(): Int {
return todoList.count()
}
inner class TodoHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val todo = itemView.findViewById<TextView>(R.id.texttodo)
}
}
package com.example.class1
data class Todoitem(var todo:String)
해당 adapter는 recyclerview와 item todo를 이어주기 위한 어뎁터로
onCreateViewHolder | 뷰가 만들어질 때 호출되는 메소드 레이아웃을 인플레이트해서 뷰 홀더를 리턴함 |
onBindViewHolder | 뷰가 바인드될 때 호출되는 메소드 . 데이터 소스에서 가져온 데이터를 사용하여 아이템의 뷰에 값을 설정함 |
getItemCount | 표시할 아이템의 갯수 |
+ TodoHolder라는 inner class를 선언해서 Holder를 직접 설정해주었다.
이런 과정을 거친 뒤
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_todo, container, false)
val recyclerView = rootView.findViewById<RecyclerView>(R.id.todo_recyclear)
var todoList = arrayListOf<Todoitem>()
for(i in 1 .. 100) {
todoList.add(Todoitem("todo ${i}"))
}
val todoAdapter=TodoAdapter(todoList)
recyclerView.adapter = todoAdapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
return rootView
}
TodoFragment로 돌아와서 onCreateView에서 해당 UI를 그려주도록 한다.
fragment의 레이아웃을 가져온 뒤 recycleview를 불러온다.
이후 recyclearview를 adapter를 통해서 item과 연결해준 뒤
item에 있는 textview에 todoList에 있는 값들을 넣어 출력하도록 한다.
이후 rootView를 return하여 해당 UI가 fragment를 호출했을 때 보일 수 있도록 한다.
결과물
참고 블로그
https://hanyeop.tistory.com/196
[Android] ViewPager2와 TabLayout 사용하여 레이아웃 만들기
탭과 뷰페이저를 사용하면 스와이프해서 다른 프래그먼트를 볼 수 있는 탭을 만들 수 있다. 사용해보기 종속성 추가 android { buildFeatures { viewBinding true } } dependencies { // 뷰페이저 2 implementation "andro
hanyeop.tistory.com
https://uknowblog.tistory.com/29
[안드로이드/코틀린] 리사이클러뷰(RecyclerView) 사용법 및 예제
리사이클러뷰(RecyclerView) 리사이클러뷰는 안드로이드에서 리스트를 만들기 위해 사용되는 뷰 입니다. 리스트를 만들기 위해 사용된다는 점에서 리스트뷰(ListView)와 비슷하지만, 뷰를 재활용(Recyc
uknowblog.tistory.com
https://developer.android.com/guide/topics/ui/layout/recyclerview?hl=ko
RecyclerView로 동적 목록 만들기 | Android 개발자 | Android Developers
컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. RecyclerView로 동적 목록 만들기 Android Jetpack의 구성요소 RecyclerView를 사용하면 대량의 데이터 세트를 효율적
developer.android.com
https://developer.android.com/guide/navigation/navigation-swipe-view-2?hl=ko
ViewPager2를 사용하여 탭으로 스와이프 뷰 만들기 | Android 개발자 | Android Developers
ViewPager2를 사용하여 탭으로 스와이프 뷰 만들기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 스와이프 뷰를 사용하면 손가락의 가로 동작이나 스와이프
developer.android.com
오늘 푼 문제
https://clockstillticktockticktock.tistory.com/48
프로그래머스 영어가 싫어요 코틀린
1.문제 https://school.programmers.co.kr/learn/courses/30/lessons/120894 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이
clockstillticktockticktock.tistory.com