Tạo màn hình Splash Screen sử dụng Physics Animation

1. Giới thiệu

Là một nhà phát triển, tôi cũng giống như mọi người khác luôn luôn cố gắng tìm hiểu và nghiên cứu các tính năng hay ho của các ứng dụng Android khác và thiết kế lại các tính năng đó trên ứng dụng của tôi. Ngày hôm qua tôi tải ứng dụng ShowBox, Một ứng dụng streaming phim và TV. Show Box Splash Screen

Sau khi nhìn thấy màn hình ở trên có vẻ thú vị. Tôi quyết định làm 1 splash screen gần giống như thế này. Tôi chia hiệu ứng này thành các phần

  1. Một hiệu ứng rotation xoay quanh trục (0,0) của màn hình.
  2. Tạo 1 hiệu ứng Translate xuống phía bên dưới màn hình. Trong bài viết này, tôi sẽ giới thiệu cho mọi người về cách mà tôi làm ra màn hình splash giống như cái ảnh bên dưới

Cảm ơn Google đã giới thiệu về Physics Based Animation tại Google I/O 2017. Để tôi có thể sử dụng nó tạo ra màn hình splash ở trên.

2. Physics Based Animation là gì. Và nó khác biết thế nào so với các Animation còn lại?

Cho tới thời điểm hiện tại, thì chúng ta hay nói cách khác là những nhà phát triển Android thì cũng đã có những APIs để sử dụng Animation như Value Animators, ObjectAnimator. Khi sử dụng 2 class này chúng ta phải dùng các interpolators khác nhau để điều khiển sự thay đổi của các animations. Chúng ta bị thiếu một điều đó là mỗi khi một sự kiện animation kết thúc chúng phải trải qua những đoạn mã phực tạp. Và khi phải xử lý những animation liên tiếp nhau thì chúng ta phải đổi mặt với việc tạo ra những đoạn code khổng lồ. Và giống như bức ảnh Ohhh my code!!!!!! Ohhhhh my code!!!!!!

Và Bây giờ có sự xuất hiện của Physics Animation :

Google đã tạo ra những đối tượng Animation này để cung cấp trải niệm thực tế hơn cho người dùng của họ. Tất cả những animation này đều được hỗ trợ tương thích ngược đến API 16. Để bắt đầu sử dụng các Animation này chỉ cần thêm thư viện physics-based-support-library vào trong file build.gradle của bạn mà thôi

compile "com.android.support:support-dynamic-animation:25.4.0"

Bây giờ bạn chẳng cần phải định nghĩa bất kỳ duration hoặc một vài thuộc tính nào đó của animation cả. F76orce của bạn đã được tạo ra để xử lý trong nội tại animation rồi.

Physics based animation API đã cung cấp 2 kiểu Animation :

  1. Spring Animation : Các Animation được điều khiển bởi Spring Force. Nơi tất cả các vận tốc trong animation của bạn sẽ phải phụ thuộc vào Spring Force. Bạn sẽ phải định nghĩa tất cả các thuộc tính của Spring Force bao gồm cả damping ratiostiffness. API đã cung cấp các kiểu hằng số khác nhau để chúng ta có thể thiết lập chúng một cách dễ dàng.

  2. Fling Animations Thuộc tính Animation của View được điều khiển bởi Friction force. Fling Animation bắt đầu bởi một momen lực ban đầu và sau đó dần dần chậm lại. Nó tuân theo các định luật ma sát là lực ma sát tỉ lệ với vận tốc của vật thể do đó nó dần dần làm chậm vật thể lại. Trong bài viết này, tôi sẽ giới thiệu Sping Animation, chỉ cần thế là đã đủ để làm được màn splash screen như ban đầu tôi có ý định làm. Thôi nói nhiều quá, giờ tới thời gian code thôi các bạn nhỉ :3.

3. Bắt đầu code thôi.

1. Tạo Spring Force và triển khai nó vào trong Spring Animation

springForce = SpringForce(0f)
relative_layout.pivotX = 0f
relative_layout.pivotY = 0f
val springAnim = SpringAnimation(relative_layout, DynamicAnimation.ROTATION).apply {
      springForce.dampingRatio = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
      springForce.stiffness = SpringForce.STIFFNESS_VERY_LOW
}
springAnim.spring = springForce
springAnim.setStartValue(80f)
  • Ở đoạn code bên trên chúng ta đã khởi tạo Spring Force với một contructor định nghĩa vị trí của Force với giá trị float.
  • Chúng ta xác định trục quay cho layout của activity là đối tượng tương đối. Nó sẽ là (0,0) bởi vì chúng ta muốn quay vòng layout về gốc tọa độ.
  • Bắt đầu khởi tạo SpringAnimationcần phải cung cấp một vài tham số sau :
    • Cung cấp View mà bạn muốn sử dụng SpringAnimation.
    • DynamicAnimation sẽ cho chúng ta biết thuộc tính nào của chúng ta sẽ animate. Đó chính là Rotation trong trường hợp của chúng ta. Và bây giờ tôi cũng phải cảm ơn Kotlin đã tạo ra cho chúng ta từ khóa apply và cung cấp block hỗ trợ chúng ta định nghĩa thuộc tính của Spring Force bên trong nó. Trong bài viết này tôi dùng giá trị DAMPING_RATIO_HIGH_BOUNCY để set Damping ratioSTIFFNESS_VERY_LOW để set cho stiffness. DAMPING_RATIO_HIGH_BOUNCY là để các giao động ở mức độ cao nhất. Và stiffness được set bằng STIFFNESS_VERY_LOW thì sẽ làm cho các đối tượng di chuyển từ từ quay lại vị trí ban đầu.
  • Và bây giờ cuối cùng chúng ta sẽ nói về Spring Animation . Chúng ta cùng set các thuộc tính của của Spring Force. Chúng ta đã thực hiện và thiết lập một vài giá trị khởi đầu của animation.

2. Khởi tạo DynamicAnimation.OnAnimationEndListener :

Bây giờ chúng ta đã định nghĩ rằng layout quay quanh trục (0,0) với giá trị stiffnessdamping ratio được định nghĩa trước và giờ chúng ta cần di chuyển layout xuống bên phía dưới màn hình hay sau Spring Animation kết thúc. Với mục định này. API của chúng ta đã cung cấp cho chúng ta 2 Listeners :

  • OnAnimationUpdateListener : Phương thức này được sử dụng để nhận các thay đổi thuộc tính trong tiến trình chạy của animation
  • OnAnimationEndListener : Phương thức này được sử dụng để thông báo sự kiện kết thúc Animation khi đã được đăng ký. Trong ứng dụng của chúng ta, chúng ta mong muốn bắt đầu dịch chuyển layout sau khi Spring Animation kết thúc vì vậy chúng ta đăng ký OnAnimationEndListener. Sau khi kết thúc Spring Animation chúng ta sẽ dịch chuyển layout sang bước tiếp theo.
springAnim.addEndListener(object : DynamicAnimation.OnAnimationEndListener {
                override fun onAnimationEnd(animation: DynamicAnimation<out DynamicAnimation<*>>?, 
                                            canceled: Boolean, value: Float, velocity: Float) {
        //Translation code will be here
})

3. Di chuyển layout sau khi nhận được sự kiện kết thúc và mở activity thứ 2 :

Bây giờ trong OnAnimationEndListener chúng ta sẽ dùng ViewPropertyAnimator là một class có sẵn trong android để thực hiện animation của một view chỉ với một vài vòng code ngắn.

override fun onAnimationEnd(animation: DynamicAnimation<out DynamicAnimation<*>>?, canceled: Boolean, value: Float, velocity: Float) {
      val displayMetrics = DisplayMetrics()
      windowManager.defaultDisplay.getMetrics(displayMetrics)
      val height = displayMetrics.heightPixels.toFloat()
      val width = displayMetrics.widthPixels
      relative_layout.animate()
                     .setStartDelay(1)
                     .translationXBy(width.toFloat() / 2)
                     .translationYBy(height)
                     .setListener(object : Animator.AnimatorListener {
                                   override fun onAnimationRepeat(p0: Animator?) {

                                    }

                                   override fun onAnimationEnd(p0: Animator?) {
                                     val intent = Intent(applicationContext, MainActivity::class.java)
                                     finish()
                                     startActivity(intent)
                                     overridePendingTransition(0, 0)
                                    }

                                  override fun onAnimationCancel(p0: Animator?) {

                                   }

                                override fun onAnimationStart(p0: Animator?) {

                                 }

                     })
                            .setInterpolator(DecelerateInterpolator(1f))
                            .start()
                }

Tôi bắt đầu nói về từng bước một nhé :

  • Đầu tiên chúng ta lấy lấy widthheight của màn hình, để chúng ta có thể có số liệu dịch chuyển.
  • Tôi sử dụng hàm animate() của Relative Layout. Nó sẽ trả về cho tôi đối tượng ViewPropertyAnimator.
  • Sau khi gọi animate(), chúng ta sẽ gọi setStartDelay để tạo thời gian delay trước khi bắt đầu Animation, Sau đó chúng ta tạo các thuộc tính translation cả 2 chiều X và Y theo tương ứng với widthheight của màn hình mà ta mới lấy được ở bên trên.
  • Sau khi thiết lập các thuộc tính của Animation. Chúng ta set thêm Listener vào trong ViewPropertyAnimator để lấy callback OnAnimationEnd và hiển thị Activity thứ 2 ngay khi callback OnAnimationEnd được gọi. P/s: Đừng quên thêm overridePendingTransition (0, 0) sau khi gọi startActivity(). Để báo cho Window Manager vô hiệu hóa activity transaction ở Activity thứ 2.
  • Sau đó cuối cùng ở ViewPropertyAnimator chúng ta thiết lập Interpolator và gọi start().

4. Cuối cùng gọi hàm start() Sping Animation của bạn.

Bây giờ Splash Screen của bạn đã sắn sàn có thể chạy được rồi. Và bạn có thể check kết quả. Để có thể tìm hiểu tốt hơn bạn có thể tìm source code tại Github Reposity

Để có tìm hiểu nhiều bài viết hay hơn nữa bạn có thể tới link bên dưới để xem nhiều điều hay ho hơn nữa. Nguồn : https://android.jlelse.eu/splash-screen-using-physics-animation-4bd98eedfe04