본문 바로가기
안드로이드 자바

[Android][JAVA]Shimmer 사용한 스켈레톤 UI 로딩화면 구현

by teamnova 2023. 7. 18.
728x90

안녕하세요 이번시간에는 안드로이드에서 로딩화면을 보여주는 애니메이션 중 하나인 스켈레톤 UI를 구현해보겠습니다.

 

 

Shimmer 는 Android 앱의 View에 효과를 추가하는 라이브러리입니다.

참고 url은 밑에 남기도록 하겠습니다.

 

build.gradle(Module :app) 파일을 열어 다음과 같이 종속성을 추가합니다

build.gradle(Module :app)

dependencies {
    // RecyclerView + retrofit
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'com.squareup.retrofit2:retrofit:2.6.4'
    implementation 'com.squareup.retrofit2:converter-scalars:2.6.4'
    implementation 'com.github.bumptech.glide:glide:4.10.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'


    //Skeleton UI
    implementation 'com.facebook.shimmer:shimmer:0.5.0'

    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.9.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

 

로딩 시 보여줄 layout을 작성합니다.

list_row_skeleton.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="4dp"
    app:cardCornerRadius="4dp">
    <LinearLayout
        android:background="#DFDEDE"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/image_view"
            android:layout_width="150dp"
            android:layout_height="80dp"
            android:scaleType="centerCrop"/>

        <TextView
            android:id="@+id/text_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="8dp"
            android:gravity="center"/>
    </LinearLayout>
</androidx.cardview.widget.CardView>

 

다음은 리사이클러뷰의 아이템으로 들어갈 레이아웃을 작성합니다.

list_row_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="4dp"
    app:cardCornerRadius="4dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/image_view"
            android:layout_width="150dp"
            android:layout_height="80dp"
            android:scaleType="centerCrop"/>

        <TextView
            android:id="@+id/text_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="8dp"
            android:gravity="center"/>
    </LinearLayout>
</androidx.cardview.widget.CardView>

 

이제 mainActivity의 레이아웃을 다음과 같이 작성합니다.

activity_main.xml

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:padding="4dp">
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:nestedScrollingEnabled="false"
                tools:listitem="@layout/list_row_main"/>
            <!-- 스켈레톤 UI로 표시될 뷰들을 추가합니다 -->
            <com.facebook.shimmer.ShimmerFrameLayout
                android:id="@+id/shimmer_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:orientation="vertical">
                    <include layout="@layout/list_row_skeleton" />
                    <include layout="@layout/list_row_skeleton" />
                    <include layout="@layout/list_row_skeleton" />
                    <include layout="@layout/list_row_skeleton" />
                    <include layout="@layout/list_row_skeleton" />
                    <include layout="@layout/list_row_skeleton" />
                    <include layout="@layout/list_row_skeleton" />
                    <include layout="@layout/list_row_skeleton" />
                </LinearLayout>
            </com.facebook.shimmer.ShimmerFrameLayout>

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

 

그 다음 MainActivity.java 파일에서 레트로핏을 통해 샘플 데이터를 갖고오고,

로딩되는 동안에는 스켈레톤UI가 보이고, 된 후에는 리사이클러뷰가 보이도록 설정합니다.

 

MainActivity.java 의 전체 코드는 다음과 같습니다

package com.example.stickcode;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.facebook.shimmer.ShimmerFrameLayout;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;

public class MainActivity extends AppCompatActivity {
    RecyclerView recyclerView;

    ArrayList<MainData> dataArrayList = new ArrayList<>();
    MainAdapter adapter;

    // 1페이지에 10개씩 데이터를 불러온다
    int page = 1, limit = 10;
    private String TAG="MainActivity";
    private ShimmerFrameLayout shimmer_layout;
    private boolean isLoading=false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = findViewById(R.id.recycler_view);
        shimmer_layout = findViewById(R.id.shimmer_layout);

        adapter = new MainAdapter(dataArrayList,this);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
        showView(isLoading);
        getData(page, limit);

    }

    private void getData(int page, int limit) {
        Log.d(TAG, "getData: ");        // 레트로핏 초기화
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://picsum.photos/")
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

        MainInterface mainInterface = retrofit.create(MainInterface.class);
        Call<String> call = mainInterface.string_call(page, limit);
        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                Log.d(TAG, "onResponse: "+response);
                Log.d(TAG, "onResponse: "+response.body());
                if (response.isSuccessful() && response.body() != null) {
                    try {
                        JSONArray jsonArray = new JSONArray(response.body());
                        isLoading=true;
                        parseResult(jsonArray);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                Log.d(TAG, "onFailure: ");
            }
        });


    }

    private void parseResult(JSONArray jsonArray){
        Log.d(TAG, "parseResult: "+jsonArray.length());
        for (int i = 0; i < jsonArray.length(); i++) {
            try {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                MainData data = new MainData(
                        jsonObject.getString("download_url"),
                        jsonObject.getString("author")
                );
                dataArrayList.add(data);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        showView(isLoading);
    }
    void showView(Boolean isData){
        if(isData){
            shimmer_layout.stopShimmer();
            recyclerView.setVisibility(View.VISIBLE);
            shimmer_layout.setVisibility(View.GONE);
        }else {
            shimmer_layout.startShimmer();
            recyclerView.setVisibility(View.GONE);
            shimmer_layout.setVisibility(View.VISIBLE);
        }
    }
}

 

리사이클러뷰 관련은 밑의 링크를 통해 확인하시면 됩니다. 감사합니다

 

https://stickode.tistory.com/69

 

[Java][Android] 리사이클러뷰에 페이징 적용하기

이번 포스팅에선 리사이클러뷰에 간단하게 페이징을 적용해 보겠습니다. 먼저 의존성 문구를 앱 수준 gradle 파일에 추가해줍니다. 레트로핏으로 네트워크 통신을 한 다음, 이미지를 받아와 리사

stickode.tistory.com

 

http://facebook.github.io/shimmer-android/

 

Shimmer for Android

About Shimmer is an Android library that provides an easy way to add a shimmer effect to any view in your Android app. It is useful as an unobtrusive loading indicator that was originally developed for Facebook Home. Watch Introductory Video Shimmer for An

facebook.github.io