-
ViewPager와 PageTransformer를 활용한 Intro Screen안드로이드 2019. 4. 16. 11:22
이번 포스팅의 주제는 ViewPager와 PageTransformer를 활용하여 애니메이션이 들어간 Intro Screen을 만들어보도록 하겠습니다.
시작에 앞서서 Google Drive의 Intro를 보시겠습니다.
Google Drive Intro
Google Drive Intro 위는 Google Drive의 Intro인데요. 실제로 보시면 기존의 ViewPager보다는 좀 더 사용자와 인터렉션이 더욱 원할히 할 수 있습니다.
사용자의 스와이핑에 맞춰서 화면의 색이 변하고 페이지 내의 object들이 서로 다른 애니메이션 효과를 가지고 이동하는 것을 볼 수 있습니다. 이것을 보통 Parallax 스크롤이라고 합니다.
일반적인 방식으로 ViewPager를 구현해 보면 아래와 같습니다.
Basic Sample 기본적으로 View는 3가지 Object로 이루어져 있습니다.
-
Title
-
Icon
-
Description
위의 Sample을 보면 처음의 Google Drive에 비하면 많이 부족하고 심심한 것을 볼 수 있습니다.
그럼 어떻게 해야 화려한 애니메이션 효과를 줄 수 있을까요? 답은 PageTransformer 를 이용하는 것입니다.
PageTransformer 활용
PageTransformer를 활용하면 아래와 같은 결과를 나타낼 수 있습니다.
ViewPager With PageTransformer 위를 보시면 스와이핑에 맞춰서 Title과 Description은 가만히 있고 아이콘만이 이동하면서,
바탕화면의 색이 그라디에이션 효과로 바뀌는 것을 볼 수 있습니다.위의 화면을 구현하기 위해서 중요한 부분은 2가지가 있습니다.
첫번째, PageTransformer의 transformPage(View page, float position)
ViewPager.PageTransformer | Android Developers
ViewPager.PageTransformer public static interface ViewPager.PageTransformer android.support.v4.view.ViewPager.PageTransformer A PageTransformer is invoked whenever a visible/attached page is scrolled. This offers an opportunity for the application to apply
developer.android.com
두번째, Gradation 효과를 주기 위한 ArgbEvaluator 가 있습니다.
ArgbEvaluator | Android Developers
ArgbEvaluator public class ArgbEvaluator extends Object implements TypeEvaluator java.lang.Object ↳ android.animation.ArgbEvaluator This evaluator can be used to perform type interpolation between integer values that represent ARGB colors. Summary Publi
developer.android.com
transformPage메서드는 현재 해당하는 page의 View 정보와 해당 page의 position 정보가 있습니다.
아래는 SorceCode입니다
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewpager.adapter = IntroAdapter(supportFragmentManager) viewpager.setPageTransformer(false, IntroPageTransformer(viewpager)) } }
const val BACKGROUND_COLOR = "backgroundColor" const val PAGE = "page" class IntroFragment : Fragment() { private var mBackgroundColor: Int? = null private var mPage: Int? = null companion object { fun newInstance(backgroundColor: Int, page: Int): IntroFragment { val frag = IntroFragment() val bundle = Bundle() bundle.putInt(BACKGROUND_COLOR, backgroundColor) bundle.putInt(PAGE, page) frag.arguments = bundle return frag } } fun getBackgroundColor(): Int? = mBackgroundColor override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBackgroundColor = arguments?.getInt(BACKGROUND_COLOR) mPage = arguments?.getInt(PAGE) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = if (mPage == 0) inflater.inflate(R.layout.activity_first, container, false) else inflater.inflate(R.layout.activity_second, container, false) view.tag = mPage return view } }
class IntroAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) { lateinit var frag1: IntroFragment lateinit var frag2: IntroFragment override fun getItem(position: Int): Fragment { when (position) { 0 -> { frag1 = IntroFragment.newInstance(Color.parseColor("#03A9F4"), position) return frag1 } else -> { frag2 = IntroFragment.newInstance(Color.parseColor("#4CAF50"), position) return frag2 } } } fun getFragmentBackgroundColor(position: Int): Int? { when (position) { 0 -> return frag1.getBackgroundColor() else -> return frag2.getBackgroundColor() } } override fun getCount(): Int = 2 }
class IntroPageTransformer(var viewPager: ViewPager) : ViewPager.PageTransformer, ViewPager.OnPageChangeListener { private val argbEvaluator: ArgbEvaluator private var color: Int = -1 init { viewPager.addOnPageChangeListener(this) argbEvaluator = ArgbEvaluator() } override fun onPageScrollStateChanged(state: Int) { //Not Use } override fun onPageSelected(position: Int) { //Not Use } override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { color = argbEvaluator.evaluate(positionOffset, (viewPager.adapter as IntroAdapter).getFragmentBackgroundColor(position), (viewPager.adapter as IntroAdapter).getFragmentBackgroundColor(position + 1)) as Int viewPager.setBackgroundColor(color) } override fun transformPage(page: View, position: Float) { val pageWidth = page.width val pageWidthTimesPosition = pageWidth * position val absPosition = Math.abs(position) if (position < 0) { page.title.alpha = 1.0f - absPosition page.title.translationX = -pageWidthTimesPosition * 0.92f page.des.alpha = 1.0f - absPosition page.des.translationX = -pageWidthTimesPosition * 0.92f } else { page.title.alpha = 1.0f - absPosition page.title.translationX = -pageWidthTimesPosition page.des.alpha = 1.0f - absPosition page.des.translationX = -pageWidthTimesPosition } } }
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/intro_background" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" tools:context=".MainActivity"> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/tv_icon" app:layout_constraintBottom_toTopOf="@+id/des" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/title" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/first_title" android:textColor="#ffffff" android:textSize="30dp" app:layout_constraintBottom_toTopOf="@+id/image" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/des" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/first_des" android:textColor="#ffffff" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/image" /> </androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/intro_background" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" tools:context=".MainActivity"> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/live_tv_icon" app:layout_constraintBottom_toTopOf="@+id/des" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/title" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/second_title" android:textColor="#ffffff" android:textSize="30dp" app:layout_constraintBottom_toTopOf="@+id/image" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/des" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/second_des" android:textColor="#ffffff" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/image" /> </androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?> <androidx.viewpager.widget.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> </androidx.viewpager.widget.ViewPager>
위의 전체 소스코드는 깃허브에 올려놓았습니다.
세계 최강을 꿈꾸는 안드로이드 Front-End 개발자입니다.
Github 주소: github.com/rkswlrbduf
이전 블로그 주소: blog.naver.com/rkswlrbduf => 블로그 이전중...
'안드로이드' 카테고리의 다른 글
Android App With Multi Module (0) 2019.04.18 CustomView - BottomNavigationView (0) 2019.04.14 아키텍처 패턴 - RAW, MVC, MVP (1) 2019.04.12 안드로이드 생명주기-Android LifeCycle (0) 2019.04.12 Android Q - RoleManager (0) 2019.04.12 댓글
-