이번 팀과제인 MomenTravel은 Youtube Api를 사용하여 여행지와 관심사를 선택하면 해당 키워드로 필터링 된 동영상을 보여주는 앱이다. 키워드로 api를 호출하고 결과 리스트를 보여주는 과정에 로딩 화면이 있으면 좋겠다고 생각하여 세 개의 점이 번갈아가며 크기가 커지는 로딩 애니메이션을 만들었다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="16dp"
android:layout_weight="1"
android:gravity="center|bottom"
android:orientation="horizontal"
android:padding="10dp">
<ImageView
android:id="@+id/fitst_dot"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_margin="4dp"
android:background="@drawable/circle_shape" />
<ImageView
android:id="@+id/second_dot"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_margin="4dp"
android:background="@drawable/circle_shape" />
<ImageView
android:id="@+id/third_dot"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_margin="4dp"
android:background="@drawable/circle_shape" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center|top"
android:text="회원님을 위한 동영상을 찾는 중..."
android:textSize="14sp" />
</LinearLayout>
Interpolator는 시작시점과 종료시점까지의 변화 과정을 어떤식으로 표현 할 것 인가에 대한 것을 Animation으로 정의한 것이다.
class LoadingDialogFragment : DialogFragment() {
private var _binding: FragmentLoadingBinding? = null
private val binding get() = _binding!!
private val dots by lazy {
listOf(binding.fitstDot, binding.secondDot, binding.thirdDot)
}
private val handler = Handler(Looper.getMainLooper())
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentLoadingBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpWindowAttributes()
startLoadingAnimation()
}
// Dialog Window 속성을 구성
private fun setUpWindowAttributes() {
val params = dialog?.window?.attributes
params?.width = ViewGroup.LayoutParams.MATCH_PARENT
params?.height = ViewGroup.LayoutParams.MATCH_PARENT
dialog?.window?.attributes = params
dialog?.window?.setBackgroundDrawableResource(android.R.color.white)
}
// 점 이미지뷰의 반복 애니메이션을 시작
private fun startLoadingAnimation() {
var dotIndex = 0
handler.post(object : Runnable {
override fun run() {
animateDot(dots[dotIndex])
dotIndex = (dotIndex + 1) % dots.size
handler.postDelayed(this, 500) // 500ms 간격으로 변경
}
})
}
// 점 이미지뷰의 크기 조정 애니메이션을 수행
private fun animateDot(dot: ImageView) {
val scaleX = ObjectAnimator.ofFloat(dot, "scaleX", 1.0f, 1.5f, 1.0f)
val scaleY = ObjectAnimator.ofFloat(dot, "scaleY", 1.0f, 1.5f, 1.0f)
/**
* AccelerateDecelerateInterpolator : AccelerateInterpolator와 DecelerateInterpolator를 합친 효과를 나타낸다.
* AccelerateInterpolator : 시작지점에서 가속하여 종료지점에 도달한다.
* DecelerateInterpolator : 종료지점에 도달할 수록 속도가 느려진다.
*/
scaleX.interpolator = AccelerateDecelerateInterpolator()
scaleY.interpolator = AccelerateDecelerateInterpolator()
scaleX.duration = 500 // 애니메이션 지속 시간 (ms)
scaleY.duration = 500 // 애니메이션 지속 시간 (ms)
scaleX.start()
scaleY.start()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
// Api 호출이 시작되면 LoadingDialogFragment를 보여준다.
private fun showLoadingActivity() {
loadingDialog = LoadingDialogFragment()
loadingDialog?.show(parentFragmentManager, "LoadingDialog")
}
// 데이터 로딩이 완료 되면 LoadingDialogFragment를 dismiss 한다.
private fun closeLoadingActivity() {
loadingDialog?.dismiss()
}