목차
0. Dependency
1. ViewPager2 in XML
2. ViewPager2 Adapter
3. ViewPager2 in Code
4. Disable Touch Swipe
5. OnPageChangeCallback
6. Move Page Programmatically
0. Dependency
dependencies {
implementation "androidx.viewpager2:viewpager2:1.0.0"
}
ViewPager2 를 사용하려는 프로젝트가 Androidx 패키지를 전반적으로 사용하고 있다면 ViewPager2 의 Dependency 를 따로 추가해줄 필요는 없다. 만약, ViewPager2 가 인식되지 않는다면 Dependency 를 추가한다.
1. ViewPager2 in XML
...
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/my_viewpager2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
...
ViewPager2 를 넣고 싶은 XML 파일 내 위치에 위와 같이 넣어주면된다. 기본적인 위젯 설정(id, padding, margin 등등) 은 개발 목적에 맞게 추가로 넣어주면 된다.
2. ViewPager2 Adapter
class ViewPager2Adapter(
private val context: FragmentActivity,
private val fragmentList: List<Fragment>
) : FragmentStateAdapter(context) {
override fun getItemCount(): Int = fragmentList.size
override fun createFragment(position: Int): Fragment = fragmentList[position]
}
ViewPager2 를 사용해서 일련의 Fragment 들을 슬라이드 형식으로 보여주고 싶다면, FragmentStateAdapter 를 상속받아서 Adapter 를 구현한다. 부모 클래스인 FragmentStateAdapter 는 FragmentActivity 형의 인자값이 필요하므로, 구현하고자 하는 Adapter 의 생성자를 통해서 부모 클래스로 전달할 인자값을 받아준다. FragmentActivity 는 AppCompatActivity 의 부모 클래스이므로, Adapter 를 사용하는 Activity 가 AppCompatActivity 를 상속받았다면 Activity 를 그대로 인자로 전달한다.
FragmentStateAdapter 를 상속받았다면, "getItemCount()" 와 "createFragment(position: Int)" 메소드를 구현해줘야한다. "getItemCount" 는 RecyclerView 의 getItemCount 와 같이 Adatper 에서 보여주고자 하는 화면의 개수(List 의 크기) 를 반환해주도록 한다. 그리고 "createFragment()" 는 현재 페이지에서 출력하고자 하는 Fragment 를 반환해주도록 구현한다.
3. ViewPager2 in Code
1, 2 단계를 거쳤다면, 이제 Code 에서 View 의 ViewPager2 와 Adapter 를 연결해준다. 위에서 구현한 ViewPager2Adapter 클래스는 FragmentActivity 형의 인자값과 List<Fragment> 형의 인자가 필요하다.
3-1) ViewPager2 변수 선언 및 초기화
...
val viewPagerAdapter = ViewPager2Adapter(this@MyActivity, fragmentList)
...
위에서 언급했듯이, AppCompatActivity 의 부모클래스가 FragmentActivity 이므로, Adapter 를 선언하는 Activity 가 AppCompatActivity 를 상속받았다면 그대로 this 를 써주면 된다. 그리고 List<Fragment> 형의 fragmentList 변수를 넣어준다. 두번째 인자값은 필수는 아니므로, 만약 List<Fragment> 를 Adapter 내부에서만 사용하고 싶다면 Adapter 내부에 fragmentList 를 선언 및 초기화 해주고, 인자값은 전달하지 않아도 된다. 즉, 첫번째 인자값인 FragmentAcitivty 변수는 필수적이고, 그 외에는 Adapter 를 생성하면서 필요한 값들을 전달하면 된다.
만약 Adapter 를 전역 변수로 사용하고 싶은데, val 로 선언하고 싶다면 lazy 를 사용하여 선언해주면 된다.
...
private val viewPagerAdapter by lazy {
ViewPager2Adapter(this@MyActivity, fragmentList)
}
...
3-2) ViewPager2 View 와 Adapter 연결
// No ViewBinding
val viewPager2 = findViewById(R.id.my_viewpager2)
viewPager2.adapter = viewPager2Adapter
// ViewBinding
binding.myViewpager2.adapter = viewPager2Adapter
ViewBinding 을 사용하지 않을 경우 위쪽 코드를 사용하고, ViewBinding 이 적용된 상태라면 아래 코드를 사용하면 된다. 이 정도까지 구현하면, fragmentList 에 있는 Fragment 들을 슬라이드 방식으로 볼 수 있다. 이제 4번째 파트부터는 ViewPager2 를 직접 사용하면서 추가로 구현한 정보들을 정리한다.
4. Disable Touch Swipe
// No ViewBinding
val viewPager2 = findViewById(R.id.my_viewpager2)
viewPager2.isUserInputEnabled = false
...
// ViewBinding
binding.myViewpager2.isUserInputEnabled = false
...
ViewPager2 는 기본적으로 터치 스와이프 방식으로 페이지 이동이 가능하다. 그러나, 회원가입 같이 특정 조건을 만족해야 페이지를 넘겨야하는 경우, 터치 스와이프 방식보단 버튼으로 페이지를 넘기는 방식이 더 좋을 것이다. 그럴 때는 코드 내 ViewPager2 위젯의 변수를 사용해서 "isUserInputEnabled" 값을 false 로 설정해주면 된다.
5. OnPageChangeCallback
val viewPager2 = findViewById(R.id.my_viewpager2)
viewPager2.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback() {
override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)
}
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
}
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
}
})
...
ViewPager2 의 Callback 은 Interface 타입이 아니라 abstract class 타입이다. 따라서, 익명 클래스를 구현해서 "registerOnPageChangeCallback()" 메소드의 인자값으로 전달한다. OnPageChangeCallback 내부의 "onPageScrollStateChanged()", "onPageScrolled()", "onPageSelected()" 메소드들은 Default 로 구현되어있으므로, 무조건 3개의 함수를 override 하지 않아도 된다. 필요한 메소드만 override 하면 된다.
5-1) onPageScrollStateChanged
public void onPageScrollStateChanged(@ViewPager2.ScrollState int state)
Scroll 상태가 변경될 때마다 호출되는 메소드이다.
[ ViewPager2 Scroll State ]
- SCROLL_STATE_IDLE : 0
- SCROLL_STATE_DRAGGING : 1
- SCROLL_STATE_SETTLING : 2
5-2) onPageScrolled
public void onPageScrolled(
int position,
float positionOffset,
@Px int positionOffsetPixels
)
현재 페이지가 스크롤 되었을 때 호출되는 메소드이다. 코드로 스크롤되거나, 유저가 터치 스와이프를 통해 스크롤 했을 때 모두 콜백된다.
- position : 현재 보여지고 있는 페이지의 Position Index 값이다.
- positionOffset : 0과 1 사이의 float 값으로, position 기준에서 페이지의 offset 값을 뜻한다.
- positionOffsetPixels : positionOffset 값을 Pixel 단위로 나타낸 값이다.
만약 페이지가 "Index 0" 에서 "Index 1" 으로 이동할 경우 Log 는 다음과 같다.
onPageScrolled: 0 / 0.0 / 0
onPageScrolled: 0 / 0.03010279 / 82
onPageScrolled: 0 / 0.04992658 / 136
onPageScrolled: 0 / 0.088472836 / 241
....... < 생략 > ......
onPageScrolled: 0 / 0.99779737 / 2718
onPageScrolled: 0 / 0.9988987 / 2721
onPageScrolled: 0 / 0.9996329 / 2723
onPageScrolled: 1 / 0.0 / 0
5-3) onPageSelected
public void onPageSelected(int position)
새로운 페이지가 선택되었을 때 호출되는 메소드이다. Transform 애니메이션이 완료되지 않아도 호출된다.
6. Move Page Programmatically
val viewPager2 = findViewById(R.id.my_viewpager2)
viewPager2.currentItem = [TARGET_PAGE_POSITION]
"4. Disable Touch Swipe" 를 적용할 경우, ViewPager2 의 페이지를 전환할 방법은 코드로 구현하는 것 밖에 없다. 이 때, ViewPager2 의 currentItem 값을 바꾸는 것으로 페이지를 이동시킬 수 있다. 코드로 페이지를 전환해도 OnPageChangeCallback 은 호출된다.
위 내용 외에 ViewPager2 를 직접 사용하면서 추가로 필요했던 부분들을 본 글에서 계속 업데이트할 예정이다.
작성일 : 2022.06.21
'Android Developer' 카테고리의 다른 글
Android Zoom Meeting SDK : 2. Integrate SDK (0) | 2022.06.30 |
---|---|
Android Zoom Meeting SDK : 1. 데모앱 살펴보기 (0) | 2022.06.24 |
[Android] 나만의 adb 명령어 모음 (0) | 2022.05.25 |
Retrofit2 의 Callback 자동 완성을 찾기 귀찮을때 (0) | 2022.05.24 |
[번역] Google Pigweed는 무엇인가? Google, IoT 개발자들을 위한 새로운 장난감을 공개하다. (0) | 2020.04.03 |