viewPager2 는 RecyclerView 를 상속받기 때문에 매우 유사함
implementation("androidx.viewpager2:viewpager2:1.0.0")
뷰페이저를 넣고 싶은 곳에 뷰페이저 추가해주기
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/mainProfile_vp"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/profileStorage_search"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:clipToPadding="false"
android:clipChildren="false">
</androidx.viewpager2.widget.ViewPager2>
나는 동일한 화면에 페이지마다 텍스트뷰와 이미지뷰만 바뀌는 것이기 때문에 뷰페이저에 들어갈 하나의 아이템을 만들어주었다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/myprofile_bg"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/multiProfile_char_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/myprofile_character"
android:layout_marginTop="120dp"
android:layout_marginLeft="90dp" />
<TextView
android:id="@+id/multiProfile_Name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="정서연"
android:fontFamily="@font/gmarketsansmedium"
android:textSize="25sp"
android:layout_marginTop="50dp"
android:layout_marginLeft="160dp"/>
<TextView
android:id="@+id/multiProfile_Number_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="010-1234-5678"
android:fontFamily="@font/gmarketsansbold"
android:textSize="15sp"
android:layout_marginTop="30dp"
android:layout_marginLeft="140dp"/>
</LinearLayout>
<ImageView
android:layout_width="150dp"
android:layout_height="100dp"
android:src="@drawable/myprofile_logo"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="530dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="110dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
페이지마다 변화를 줄 데이터인 이름과 프로필사진, 전화번호는 변수로 선언
data class MultiProfileData(
val profileImageResId: Int,
val name: String,
val phoneNumber: String
)
Adapter 는 아까 만들어놓은 틀 (화면) 에 데이터들을 차곡차곡 넣어주는 역할
내가 만든 화면의 경우,
1. ImageView 2. TextView1 3. TextView2
세 개의 위젯이 있는데 어떤 데이터를 이미지에 넣고, 어떤 데이터를 텍스트뷰에 넣을 건지 등을 정하는 부분
가장 먼저 이너클래스로 viewholder 정의하기!
multiprofile_item 의 위젯들과 인자로 전달한 데이터(위에 코드에선 item: multiprofile) 를 연결
//ListAdapter 상속받아 아이템 목록 관리/갱신
class MainProfileVPAdapter : ListAdapter<MultiProfileData, MainProfileVPAdapter.MainItemViewHolder>(MainListDiffCallback()) {
// onCreateViewHolder: 뷰홀더 객체 생성 및 뷰홀더 레이아웃 설정
//아이템을 뷰홀더에 연결하고 뷰홀더 생성해줌
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainItemViewHolder {
//아이템xml을 뷰바인딩 객체 생성
val binding = ItemMultiprofileBinding.inflate(LayoutInflater.from(parent.context), parent, false)
// 뷰홀더에 아이템 넣어 객체를 생성하고 반환
return MainItemViewHolder(binding)
}
// onBindViewHolder: 뷰홀더에 데이터 바인딩
//각 아이템의 위치(position)에 해당하는 데이터를 뷰홀더에 전달하여 표시
//알맞는 위치에 데이터를 뿌려주는 역할
override fun onBindViewHolder(holder: MainItemViewHolder, position: Int) {
// 뷰홀더에 데이터를 바인딩하는 함수 호출
holder.bind(getItem(position))
}
// MainItemViewHolder: 뷰홀더 클래스
inner class MainItemViewHolder(private val binding: ItemMultiprofileBinding) : RecyclerView.ViewHolder(binding.root) {
//bind: 데이터를 뷰에 바인딩하는 함수
fun bind(item: MultiProfileData) {
// 뷰바인딩을 통해 각 아이템의 데이터를 설정
binding.multiProfileCharIv.setImageResource(item.profileImageResId)
binding.multiProfileNameTv.text = item.name
binding.multiProfileNumberTv.text = item.phoneNumber
}
}
// MainListDiffCallback: 아이템 변경을 감지하는 콜백 클래스
class MainListDiffCallback : DiffUtil.ItemCallback<MultiProfileData>() {
// areItemsTheSame: 아이템이 같은지 여부를 판단
override fun areItemsTheSame(oldItem: MultiProfileData, newItem: MultiProfileData): Boolean {
// 아이템의 고유 식별자를 비교하여 같은 아이템인지 여부를 반환
return oldItem == newItem
}
// areContentsTheSame: 아이템 내용이 같은지 여부를 판단
override fun areContentsTheSame(oldItem: MultiProfileData, newItem: MultiProfileData): Boolean {
// 아이템의 내용을 비교하여 같은 내용인지 여부를 반환 (예: 이름이 같은 경우 같은 내용으로 간주)
return oldItem.name == newItem.name
}
}
}
프래그먼트와 어댑터 연결하고 리스트에 데이터 직접 넣어줌
class MainProfileFragment : Fragment() {
// ViewBinding을 사용하여 레이아웃과 바인딩된 객체 연결
lateinit var binding : FragmentMainprofileBinding
//데이터 클래스의 데이터 담을 리스트 생성
private val multiList = mutableListOf<MultiProfileData>()
//ViewPager 어댑터 생성
private val vpadapter = MainProfileVPAdapter()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// ViewBinding을 통해 프래그먼트의 레이아웃과 연결된 바인딩 객체 초기화
binding= FragmentMainprofileBinding.inflate(inflater,container,false)
//하단의 함수 실행
initViewPager()
return binding.root
}
//ViewPager 초기화 함수
private fun initViewPager(){
val multiList = mutableListOf<MultiProfileData>()
// 초기 프로필 데이터를 MutableList에 추가
multiList.add(MultiProfileData(R.drawable.myprofile_character, "1", "010-1234-5678"))
multiList.add(MultiProfileData(R.drawable.myprofile_character, "2", "010-1234-5678"))
multiList.add(MultiProfileData(R.drawable.myprofile_character, "3", "010-1234-5678"))
//어댑터 초기화
val vpadapter = MainProfileVPAdapter()
// 어댑터에 데이터 제출
vpadapter.submitList(multiList)
//xml의 뷰페이저에 어댑터 연결
binding.mainProfileVp.adapter = vpadapter
}
}