[Android] 스켈레톤 로딩 화면 구현하기 - Facebook shimmer library
Android

[Android] 스켈레톤 로딩 화면 구현하기 - Facebook shimmer library

728x90

 

 

https://www.youtube.com/watch?v=-RPvtDlKfkE

 

사용자가 어떠한 요청을 했는데 화면에 아무런 변화가 없다면 어떤 느낌을 받을까요? 요청이 제대로 들어갔는지, 앱이 고장 난 건지 사용자는 알 수가 없습니다.

따라서 데이터를 로딩 중에는 사용자가 알기 쉽게 로딩 애니메이션을 보여주는 것이 좋습니다. 로딩 애니메이션에는 스켈레톤 UI, 루프 애니메이션, 프로그래스 바 등의 다양한 방법이 있습니다.

 

 

 

 

 이번 포스팅에서는 위의 화면과 같이 스켈레톤 로딩 화면을 구현해보겠습니다. 스켈레톤 로딩 화면은 표시될 정보의 대략적인 형태를 미리 보여줘서 다음 화면까지 부드럽게 연결해주는 역할을 합니다.

 스켈레톤 로딩 화면을 구현하는 데는 여러 방법이 있지만, 가장 유명한 Facebook에서 제공하는 shimmer-android 라이브러리를 사용해보겠습니다.

 

 

 

라이브러리 추가

 먼저 shimmer-android 라이브러리를 추가해줍니다.

implementation "com.facebook.shimmer:shimmer:0.5.0"

 

 

 

layout_item.xml

 리스트에서 각각의 item을 그려줄 레이아웃을 작성합니다.

<?xml version="1.0" encoding="utf-8"?>
<layout 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">


    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="12dp">

        <ImageView
            android:id="@+id/iv_sample"
            android:layout_width="48dp"
            android:layout_height="48dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            tools:background="@color/cardview_shadow_start_color"/>

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="12dp"
            android:textStyle="bold"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constrainedWidth="true"
            app:layout_constraintBottom_toTopOf="@id/tv_email"
            app:layout_constraintStart_toEndOf="@id/iv_sample"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            tools:text="Name" />

        <TextView
            android:id="@+id/tv_email"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            app:layout_constrainedWidth="true"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintTop_toBottomOf="@id/tv_name"
            app:layout_constraintStart_toStartOf="@id/tv_name"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            tools:text="Email"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 

 

 

layout_item_shimmer.xml

 스켈레톤 로딩 화면에서 보여줄 UI를 작성해줍니다. 리스트 item의 기본 구조와 유사하게 작성합니다.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="12dp">

        <ImageView
            android:id="@+id/iv_sample"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:background="@color/cardview_shadow_start_color"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" />

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="12dp"
            android:background="@color/cardview_shadow_start_color"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constrainedWidth="true"
            app:layout_constraintBottom_toTopOf="@id/tv_email"
            app:layout_constraintStart_toEndOf="@id/iv_sample"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />

        <TextView
            android:id="@+id/tv_email"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:background="@color/cardview_shadow_start_color"
            android:layout_marginTop="4dp"
            app:layout_constrainedWidth="true"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintTop_toBottomOf="@id/tv_name"
            app:layout_constraintStart_toStartOf="@id/tv_name"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 위의 xml에서 중요한 점은 배경색을 흰색이 아닌 유색으로 지정해줘야 한다는 것입니다. 배경이 흰색이면 반짝이는 효과가 보이지 않습니다.

 

 

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_sample"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            tools:listitem="@layout/layout_item"/>

        <com.facebook.shimmer.ShimmerFrameLayout
            android:id="@+id/sfl_sample"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <include layout="@layout/layout_item_shimmer" />

                <include layout="@layout/layout_item_shimmer" />

                <include layout="@layout/layout_item_shimmer" />

                <include layout="@layout/layout_item_shimmer" />

                <include layout="@layout/layout_item_shimmer" />

                <include layout="@layout/layout_item_shimmer" />

                <include layout="@layout/layout_item_shimmer" />

                <include layout="@layout/layout_item_shimmer" />

                <include layout="@layout/layout_item_shimmer" />

                <include layout="@layout/layout_item_shimmer" />
            </LinearLayout>
        </com.facebook.shimmer.ShimmerFrameLayout>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 ShimmerFrameLayout을 사용해 스켈레톤 로딩 화면을 만들어 줍니다. ShimmerFrameLayout으로 뷰를 감싸게 되면 감싸진 뷰에 Shimmer 이펙트를 적용할 수 있습니다.

 리사이클러뷰의 item과 유사한 빈 레이아웃을 표현해주기 위해 layout_item_shimmer를 여러 개 추가해줍니다.

 

 

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private val binding: ActivityMainBinding by lazy { DataBindingUtil.setContentView(this, R.layout.activity_main) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding.rvSample.adapter = SampleAdapter()

        loadSampleData()
    }

    private fun loadSampleData() {
        lifecycleScope.launch {
            showSampleData(isLoading = true)

            delay(3000)

            val samples = getSampleList()
            (binding.rvSample.adapter as SampleAdapter).replaceAll(samples)

            showSampleData(isLoading = false)
        }
    }

    private fun showSampleData(isLoading: Boolean) {
        if (isLoading) {
            binding.sflSample.startShimmer()
            binding.sflSample.visibility = View.VISIBLE
            binding.rvSample.visibility = View.GONE
        } else {
            binding.sflSample.stopShimmer()
            binding.sflSample.visibility = View.GONE
            binding.rvSample.visibility = View.VISIBLE
        }
    }
}

 리사이클러뷰의 adapter를 설정한 뒤, loadSampleData() 메서드를 통해 데이터를 요청합니다. 서버에 데이터를 요청했다고 가정하고 3초의 딜레이를 적용해줬습니다.

 ShimmerFrameLayout의 startShimmer() 메서드를 호출하면 Shimmer 이펙트가 적용됩니다. 데이터가 전부 로딩돼서 이펙트를 해제해주고 싶다면 stopShimmer() 메서드를 호출해주면 됩니다.

 

 

 

예제 소스

https://github.com/tkdgusl94/blog-source/tree/master/Shimmer-Effect

 

GitHub - tkdgusl94/blog-source: https://leveloper.tistory.com/ 에서 제공하는 예제 source

https://leveloper.tistory.com/ 에서 제공하는 예제 source. Contribute to tkdgusl94/blog-source development by creating an account on GitHub.

github.com

 

참고

https://blog.mindorks.com/using-shimmer-effect-placeholder-in-android

 

Using Shimmer Effect Placeholder in Android

In this blog, we will demonstrate how to use Shimmer in your Android application. We will be fetching the data from the API using the Fast-Android-Networking and then displaying the data in the RecyclerView. So let’s get started!

blog.mindorks.com

 

728x90