ViewPager를 활용한 Android 전환 애니메이션 구현

앱 최초 실행 시 가이드 화면을 표시하는 기능은 많은 개발자들에게 익숙한 요구사항입니다. 이 효과는 어떻게 구현할 수 있을까요? 이번 글에서는 ViewPager를 사용하여 이미지 슬라이드쇼를 만들고, 다양한 전환 애니메이션 효과를 적용하는 방법을 살펴보겠습니다.

ViewPager는 Android에서 화면 간 전환을 처리하는 핵심 컴포넌트입니다. 자세한 설명은 생략하고 바로 실습으로 넘어가겠습니다.

기본 이미지 슬라이더 구현

먼저 간단한 레이아웃 파일부터 작성합니다:

<RelativeLayout 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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">
    
    <com.example.android_viewpager.CustomViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

다음은 메인 액티비티 구현 코드입니다:

public class MainActivity extends Activity {
    
    private CustomViewPager pagerInstance;
    int[] resourceIds = {R.drawable.guide_image1, R.drawable.guide_image2, R.drawable.guide_image3};
    List<ImageView> imageViewList = new ArrayList<ImageView>();
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pagerInstance = (CustomViewPager) findViewById(R.id.viewPager);
        
        pagerInstance.setAdapter(new PagerAdapter() {
            
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView(imageViewList.get(position));
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                ImageView imageView = new ImageView(MainActivity.this);
                imageView.setImageResource(resourceIds[position]);
                imageView.setScaleType(ScaleType.CENTER_CROP);
                container.addView(imageView);
                imageViewList.add(imageView);
                return imageView;
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }
            
            @Override
            public int getCount() {
                return resourceIds.length;
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

애니메이션 효과 적용

Google은 ViewPager에 애니메이션 효과를 추가할 수 있는 공식 API를 제공합니다. 공식 문서(링크)를 참고하여 구현해보겠습니다.

애니메이션을 적용하는 방법은 매우 간단합니다:

pagerInstance.setPageTransformer(true, new DepthPageTransformer());

깊이 기반 전환 효과를 구현한 DepthPageTransformer 클래스:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class DepthPageTransformer implements ViewPager.PageTransformer {
    
    private static final float MINIMUM_SCALE = 0.75f;

    @SuppressLint("NewApi")
    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();

        if (position < -1) {
            view.setAlpha(0);
        } else if (position <= 0) {
            view.setAlpha(1);
            view.setTranslationX(0);
            view.setScaleX(1);
            view.setScaleY(1);
        } else if (position <= 1) {
            view.setAlpha(1 - position);
            view.setTranslationX(pageWidth * -position);
            
            float scaleFactor = MINIMUM_SCALE + (1 - MINIMUM_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
        } else {
            view.setAlpha(0);
        }
    }
}

하위 버전 호환성 처리

위 코드는 Android 3.0(API level 11) 이상에서만 동작합니다. 하위 버전에서도 동일한 효과를 구현하려면 ViewHelper를 사용해야 합니다:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class CompatibleDepthPageTransformer implements ViewPager.PageTransformer {
    private static final float MINIMUM_SCALE = 0.75f;

    @SuppressLint("NewApi")
    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();

        if (position < -1) {
            ViewHelper.setAlpha(view, 0);
        } else if (position <= 0) {
            ViewHelper.setAlpha(view, 1);
            ViewHelper.setTranslationX(view, 0);
            ViewHelper.setScaleX(view, 1);
            ViewHelper.setScaleY(view, 1);
        } else if (position <= 1) {
            ViewHelper.setAlpha(view, 1 - position);
            ViewHelper.setTranslationX(view, pageWidth * -position);
            
            float scaleFactor = MINIMUM_SCALE + (1 - MINIMUM_SCALE) * (1 - Math.abs(position));
            ViewHelper.setScaleX(view, scaleFactor);
            ViewHelper.setScaleY(view, scaleFactor);
        } else {
            ViewHelper.setAlpha(view, 0);
        }
    }
}

ViewPager 소스코드를 살펴보면 버전 체크 로직이 포함되어 있어 하위 버전에서는 애니메이션이 실행되지 않습니다. 이를 해결하기 위해 ViewPager 클래스를 상속받아 커스터마이징해야 합니다:

public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) {
    // if (Build.VERSION.SDK_INT >= 11) 제거
    {
        final boolean hasTransformer = transformer != null;
        final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
        mPageTransformer = transformer;
        setChildrenDrawingOrderEnabledCompat(hasTransformer);
        if (hasTransformer) {
            mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
        } else {
            mDrawingOrder = DRAW_ORDER_DEFAULT;
        }
        if (needsPopulate) populate();
    }
}

레이아웃 파일도 수정된 클래스를 사용하도록 변경합니다:

<com.example.android_viewpager.CustomViewPager
    android:id="@+id/viewPager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

액티비티 코드도 다음과 같이 업데이트합니다:

pagerInstance = (CustomViewPager) findViewById(R.id.viewPager);

추가 애니메이션 효과

회전 효과를 구현한 예제도 함께 소개합니다:

public class RotateDownPageTransformer implements ViewPager.PageTransformer {
    private static final float MAX_ROTATION = 20F;
    private static float currentRotation = 0F;
    
    @Override
    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();

        if (position < -1) {
            ViewHelper.setAlpha(view, 0);
        } else if (position <= 0) {
            currentRotation = MAX_ROTATION * position;
            ViewHelper.setPivotX(view, pageWidth/2);
            ViewHelper.setPivotY(view, view.getMeasuredHeight());
            ViewHelper.setRotation(view, currentRotation);
        } else if (position <= 1) {
            currentRotation = MAX_ROTATION * position;
            ViewHelper.setPivotX(view, pageWidth/2);
            ViewHelper.setPivotY(view, view.getMeasuredHeight());
            ViewHelper.setRotation(view, currentRotation);
        } else {
            ViewHelper.setAlpha(view, 0);
        }
    }
}

이러한 방법들을 통해 ViewPager에 다양한 전환 애니메이션 효과를 적용할 수 있습니다. 궁금한 점이 있다면 댓글로 문의해주세요.

태그: Android ViewPager Animation UI Mobile

5월 25일 03:22에 게시됨