화면 슬라이드는 한 전체 화면에서 다른 화면으로의 전환이며 설정 마법사 및 슬라이드쇼와 같은 UI에서 일반적으로 사용됩니다. 이 주제에서는 ViewPager2
객체를 사용하여 화면 슬라이드를 실행하는 방법을 보여줍니다. ViewPager2
객체는 화면 슬라이드에 자동으로 애니메이션을 적용할 수 있습니다. 다음은 콘텐츠의 한 화면에서 다음 화면으로 전환되는 화면 슬라이드의 예입니다.
이를 건너뛰고 실제로 완벽히 작동하는 예를 보려면 GitHub에서 이 샘플 앱을 확인하세요.
ViewPager2
를 사용하려면 프로젝트에 AndroidX 종속 항목을 추가해야 합니다. 그런 다음 아래 섹션에 설명된 단계를 따릅니다.
뷰 만들기
나중에 프래그먼트의 콘텐츠에 사용할 레이아웃 파일을 만듭니다. 프래그먼트 콘텐츠의 문자열도 정의해야 합니다. 다음 예에는 텍스트를 표시하는 텍스트 뷰가 포함되어 있습니다.
<!-- fragment_screen_slide_page.xml --> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView style="?android:textAppearanceMedium" android:padding="16dp" android:lineSpacingMultiplier="1.2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/lorem_ipsum" /> </ScrollView>
프래그먼트 만들기
onCreateView()
메서드에서 만든 레이아웃을 반환하는 Fragment
클래스를 만듭니다. 그런 다음 사용자에게 표시할 새 페이지가 필요할 때마다 상위 활동에서 이 프래그먼트의 인스턴스를 만들 수 있습니다.
Kotlin
import androidx.fragment.app.Fragment class ScreenSlidePageFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View = inflater.inflate(R.layout.fragment_screen_slide_page, container, false) }
Java
import androidx.fragment.app.Fragment; ... public class ScreenSlidePageFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return (ViewGroup) inflater.inflate( R.layout.fragment_screen_slide_page, container, false); } }
ViewPager2 추가
ViewPager2
객체에는 페이지 간에 전환하는 스와이프 동작이 내장되어 있으며 기본적으로 화면 슬라이드 애니메이션을 표시하므로 개발자가 자체 애니메이션을 만들 필요가 없습니다.
ViewPager2
는 FragmentStateAdapter
객체를 표시할 새 페이지의 공급 장치로 사용하므로 FragmentStateAdapter
는 개발자가 만든 프래그먼트 클래스를 사용합니다.
시작하려면 ViewPager2
객체가 포함된 레이아웃을 만듭니다.
<!-- activity_screen_slide.xml --> <androidx.viewpager2.widget.ViewPager2 xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" />
다음을 실행하는 활동을 만듭니다.
- 콘텐츠 뷰를
ViewPager2
가 있는 레이아웃으로 설정합니다. FragmentStateAdapter
추상 클래스를 확장하는 클래스를 만들고createFragment()
메서드를 구현하여ScreenSlidePageFragment
인스턴스를 새 페이지로 제공합니다. 페이저 어댑터의 경우 어댑터에서 생성한 페이지 수를 반환하는getItemCount()
메서드를 구현해야 합니다. 예시에는 5개가 있습니다.FragmentStateAdapter
를ViewPager2
객체에 연결합니다.
Kotlin
import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity ... /** * The number of pages (wizard steps) to show in this demo. */ private const val NUM_PAGES = 5 class ScreenSlidePagerActivity : FragmentActivity() { /** * The pager widget, which handles animation and allows swiping horizontally * to access previous and next wizard steps. */ private lateinit var viewPager: ViewPager2 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_screen_slide) // Instantiate a ViewPager2 and a PagerAdapter. viewPager = findViewById(R.id.pager) // The pager adapter, which provides the pages to the view pager widget. val pagerAdapter = ScreenSlidePagerAdapter(this) viewPager.adapter = pagerAdapter } override fun onBackPressed() { if (viewPager.currentItem == 0) { // If the user is currently looking at the first step, allow the system to handle // the Back button. This calls finish() on this activity and pops the back stack. super.onBackPressed() } else { // Otherwise, select the previous step. viewPager.currentItem = viewPager.currentItem - 1 } } /** * A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in * sequence. */ private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) { override fun getItemCount(): Int = NUM_PAGES override fun createFragment(position: Int): Fragment = ScreenSlidePageFragment() } }
자바
import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; ... public class ScreenSlidePagerActivity extends FragmentActivity { /** * The number of pages (wizard steps) to show in this demo. */ private static final int NUM_PAGES = 5; /** * The pager widget, which handles animation and allows swiping horizontally to access previous * and next wizard steps. */ private ViewPager2 viewPager; /** * The pager adapter, which provides the pages to the view pager widget. */ private FragmentStateAdapter pagerAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_screen_slide); // Instantiate a ViewPager2 and a PagerAdapter. viewPager = findViewById(R.id.pager); pagerAdapter = new ScreenSlidePagerAdapter(this); viewPager.setAdapter(pagerAdapter); } @Override public void onBackPressed() { if (viewPager.getCurrentItem() == 0) { // If the user is currently looking at the first step, allow the system to handle the // Back button. This calls finish() on this activity and pops the back stack. super.onBackPressed(); } else { // Otherwise, select the previous step. viewPager.setCurrentItem(viewPager.getCurrentItem() - 1); } } /** * A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in * sequence. */ private class ScreenSlidePagerAdapter extends FragmentStateAdapter { public ScreenSlidePagerAdapter(FragmentActivity fa) { super(fa); } @Override public Fragment createFragment(int position) { return new ScreenSlidePageFragment(); } @Override public int getItemCount() { return NUM_PAGES; } } }
PageTransformer를 사용하여 애니메이션 맞춤설정
기본 화면 슬라이드 애니메이션과 다른 애니메이션을 표시하려면 ViewPager2.PageTransformer
인터페이스를 구현하여 ViewPager2
객체에 제공합니다. 인터페이스는 단일 메서드 transformPage()
를 노출합니다.
화면 전환의 각 지점에서 이 메서드는 표시되는 각 페이지(일반적으로 하나의 페이지만 표시됨)와 화면 밖의 인접 페이지에 대해 한 번씩 호출됩니다. 예를 들어 3페이지가 표시되고 사용자가 4페이지로 드래그하면 동작의 각 단계에서 2페이지, 3페이지, 4페이지에 transformPage()
가 호출됩니다.
그런 다음 transformPage()
구현에서 화면의 페이지 위치에 따라 변환해야 하는 페이지를 결정하여 맞춤 슬라이드 애니메이션을 만들 수 있습니다. transformPage()
메서드의 position
매개변수에서 페이지 위치를 가져옵니다.
position
매개변수는 지정된 페이지의 위치를 화면 중앙을 기준으로 나타냅니다. 이 매개변수는 사용자가 일련의 페이지를 스크롤할 때 변경되는 동적 속성입니다. 페이지가 화면을 채우면 위치 값은 0
입니다. 페이지가 화면 오른쪽에서 벗어나면 위치 값은 1
입니다. 사용자가 1페이지와 2페이지 사이를 스크롤하면 1페이지의 위치는 -0.5
이고 2페이지의 위치는 0.5
입니다. 화면의 페이지 위치에 따라 setAlpha()
, setTranslationX()
또는 setScaleY()
와 같은 메서드로 페이지 속성을 설정하여 맞춤 슬라이드 애니메이션을 만들 수 있습니다.
PageTransformer
를 구현한 경우 구현과 함께 setPageTransformer()
를 호출하여 맞춤 애니메이션을 적용합니다. 예를 들어 이름이 ZoomOutPageTransformer
인 PageTransformer
가 있다면 다음과 같이 맞춤 애니메이션을 설정할 수 있습니다.
Kotlin
val viewPager: ViewPager2 = findViewById(R.id.pager) ... viewPager.setPageTransformer(ZoomOutPageTransformer())
Java
ViewPager2 viewPager = findViewById(R.id.pager); ... viewPager.setPageTransformer(new ZoomOutPageTransformer());
PageTransformer
의 예는 페이지 축소 변환기 및 심도 페이지 변환기 섹션을 참고하세요.
페이지 축소 변환기
이 페이지 변환기는 인접 페이지 사이를 스크롤할 때 페이지를 축소하고 페이드 아웃합니다. 페이지가 중앙에 가까워질수록 원래 크기로 다시 커지다가 페이드인됩니다.
Kotlin
private const val MIN_SCALE = 0.85f private const val MIN_ALPHA = 0.5f class ZoomOutPageTransformer : ViewPager2.PageTransformer { override fun transformPage(view: View, position: Float) { view.apply { val pageWidth = width val pageHeight = height when { position < -1 -> { // [-Infinity,-1) // This page is way off-screen to the left. alpha = 0f } position <= 1 -> { // [-1,1] // Modify the default slide transition to shrink the page as well. val scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)) val vertMargin = pageHeight * (1 - scaleFactor) / 2 val horzMargin = pageWidth * (1 - scaleFactor) / 2 translationX = if (position < 0) { horzMargin - vertMargin / 2 } else { horzMargin + vertMargin / 2 } // Scale the page down (between MIN_SCALE and 1). scaleX = scaleFactor scaleY = scaleFactor // Fade the page relative to its size. alpha = (MIN_ALPHA + (((scaleFactor - MIN_SCALE) / (1 - MIN_SCALE)) * (1 - MIN_ALPHA))) } else -> { // (1,+Infinity] // This page is way off-screen to the right. alpha = 0f } } } } }
Java
public class ZoomOutPageTransformer implements ViewPager2.PageTransformer { private static final float MIN_SCALE = 0.85f; private static final float MIN_ALPHA = 0.5f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); int pageHeight = view.getHeight(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0f); } else if (position <= 1) { // [-1,1] // Modify the default slide transition to shrink the page as well. float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); float vertMargin = pageHeight * (1 - scaleFactor) / 2; float horzMargin = pageWidth * (1 - scaleFactor) / 2; if (position < 0) { view.setTranslationX(horzMargin - vertMargin / 2); } else { view.setTranslationX(-horzMargin + vertMargin / 2); } // Scale the page down (between MIN_SCALE and 1). view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); // Fade the page relative to its size. view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0f); } } }
심도 페이지 변환기
이 페이지 변환기는 페이지를 왼쪽으로 슬라이딩할 때 기본 슬라이드 애니메이션을 사용하고 페이지를 오른쪽으로 슬라이딩하려면 '심도' 애니메이션을 사용합니다. 이 깊이 애니메이션에서는 페이지를 페이드 아웃하고 선형으로 축소합니다.
깊이 애니메이션이 진행되는 동안 기본 애니메이션 (화면 슬라이드)이 계속 발생하므로 음의 X 변환을 사용하여 화면 슬라이드에 대응해야 합니다. 예:
Kotlin
view.translationX = -1 * view.width * position
Java
view.setTranslationX(-1 * view.getWidth() * position);
다음 예는 작동하는 페이지 변환기에서 기본 화면 슬라이드 애니메이션을 차단하는 방법을 보여줍니다.
Kotlin
private const val MIN_SCALE = 0.75f @RequiresApi(21) class DepthPageTransformer : ViewPager2.PageTransformer { override fun transformPage(view: View, position: Float) { view.apply { val pageWidth = width when { position < -1 -> { // [-Infinity,-1) // This page is way off-screen to the left. alpha = 0f } position <= 0 -> { // [-1,0] // Use the default slide transition when moving to the left page. alpha = 1f translationX = 0f translationZ = 0f scaleX = 1f scaleY = 1f } position <= 1 -> { // (0,1] // Fade the page out. alpha = 1 - position // Counteract the default slide transition. translationX = pageWidth * -position // Move it behind the left page. translationZ = -1f // Scale the page down (between MIN_SCALE and 1). val scaleFactor = (MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position))) scaleX = scaleFactor scaleY = scaleFactor } else -> { // (1,+Infinity] // This page is way off-screen to the right. alpha = 0f } } } } }
Java
@RequiresApi(21) public class DepthPageTransformer implements ViewPager2.PageTransformer { private static final float MIN_SCALE = 0.75f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0f); } else if (position <= 0) { // [-1,0] // Use the default slide transition when moving to the left page. view.setAlpha(1f); view.setTranslationX(0f); view.setTranslationZ(0f); view.setScaleX(1f); view.setScaleY(1f); } else if (position <= 1) { // (0,1] // Fade the page out. view.setAlpha(1 - position); // Counteract the default slide transition. view.setTranslationX(pageWidth * -position); // Move it behind the left page view.setTranslationZ(-1f); // Scale the page down (between MIN_SCALE and 1). float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0f); } } }
추가 리소스
ViewPager2
에 관해 자세히 알아보려면 다음 추가 리소스를 참조하세요.
샘플
- GitHub의 ViewPager2 샘플
동영상
- 페이지 넘기기: ViewPager2로 이전 (Android Dev Summit '19)