How to Implement Shimmer Load in Android

in #utopian-io7 years ago (edited)

cover.png


Facebook Shimmer

Hi, in this post, I will show you how to implement Shimmer Load in Android application. After reading this post hopefully you can implement shimmer load in your Android project. Alright let's get started.

What Will I Learn?

  • Logic of how shimmer load works.
  • Implement shimmer load in your project.

Requirements

  • Android Studio
  • Knowledge of Java

Difficulty

  • Basic

Tutorial Contents

So maybe you are wondering, what exactly is shimmer load. This is a screenshot of Youtube apps on iOS.
youtube-ios-shimmer.jpeg
Shimmer load is basically a placeholder that is shown when your apps is loading, for example when fetching data from an API.


There are a lot of shimmer load library which works a bit different, but in this post I will be using a library from Facebook called shimmer-android.


The logic behind facebook shimmer load is basically switching view between two layout. In Android it is basically playing with layout visibility.



In this tutorial, I will make an example of searching movie data from imdb API.

Curriculum

1. Install Dependency

To install this dependency, simply add implementation 'com.facebook.shimmer:shimmer:0.1.0@aar' in your application build.gradle file.


This is my entire build.gradle file:

apply plugin: 'com.android.application'
android {
    compileSdkVersion 27
    buildToolsVersion '27.0.3'
    defaultConfig {
        applicationId "com.steven.example.shimmerloadexample"
        minSdkVersion 19
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:27.0.2'
    implementation "com.android.support:recyclerview-v7:27.0.2"
    implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'
    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
    implementation 'com.github.bumptech.glide:glide:4.6.1'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

2. Create A Placeholder

The next thing is creating a placeholder for the shimmer load. For the movie list item I will have the end result looks like this:


item_movie.png


So we need to create the place holder similar to our list item. The place holder I made looks like this:


placeholder.png


This is my entire placeholder file with background colorShimmer #DDDDDD:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="160dp">

    <View
        android:id="@+id/view_image"
        android:layout_width="120dp"
        android:layout_height="match_parent"
        android:layout_margin="8dp"
        android:background="@color/colorShimmer" />

    <View
        android:id="@+id/view_title"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_alignParentEnd="true"
        android:layout_margin="8dp"
        android:layout_toEndOf="@+id/view_image"
        android:background="@color/colorShimmer" />

    <View
        android:layout_width="80dp"
        android:layout_height="24dp"
        android:layout_above="@id/view_type"
        android:layout_alignParentEnd="true"
        android:layout_margin="8dp"
        android:background="@color/colorShimmer" />

    <View
        android:id="@+id/view_type"
        android:layout_width="160dp"
        android:layout_height="24dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_margin="8dp"
        android:background="@color/colorShimmer" />

</RelativeLayout>

3. Use Placeholder

Now it's time to use the placeholder that we've created. In your activity/fragment layout add ShimmerFrameLayout with the place holder inside it. In my example I have ShimmerFrameLayout and RecyclerView, when fetching data ShimmerFrameLayout will be shown and starts its animaton, and RecyclerView will be hide. Once all the data has been fetch and added to RecyclerView, RecyclerView will be shown, and ShimmerFrameLayout will be hide and stop its animation.


My activity_main.xml file looks like this:

<?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"
    xmlns:shimmer="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical"
    tools:context="com.steven.example.shimmerloadexample.ui.MainActivity">

    <android.support.v7.widget.SearchView
        android:id="@+id/search_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:theme="@style/Theme.AppCompat.Light"
        app:queryHint="Search here" />

    <com.facebook.shimmer.ShimmerFrameLayout
        android:id="@+id/shimmer_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone"
        shimmer:duration="800">

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

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

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

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

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

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

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

        </LinearLayout>

    </com.facebook.shimmer.ShimmerFrameLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

And my 'MainActivity.java' looks like this:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    private SearchView mSearchView;
    private ShimmerFrameLayout mShimmerLayout;
    private RecyclerView mRecyclerView;
    private RecyclerViewAdapter mAdapter;
    private List<Movie> mMovieList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mSearchView = findViewById(R.id.search_view);
        mShimmerLayout = findViewById(R.id.shimmer_layout);
        mRecyclerView = findViewById(R.id.recycler_view);

        mSearchView.setIconified(false);

        mMovieList = new ArrayList<>();
        mAdapter = new RecyclerViewAdapter(this);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        mRecyclerView.setAdapter(mAdapter);

        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                fetchData();
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                return false;
            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();
        mShimmerLayout.stopShimmerAnimation();
    }

    private void fetchData() {
        mShimmerLayout.setVisibility(View.VISIBLE);
        mShimmerLayout.startShimmerAnimation();
        String keyword = mSearchView.getQuery().toString();
        keyword = keyword.replace(" ", "+");
        RetrofitSingleton.getInstance().getRestAPI().searchTitle(keyword, 1, Config.API_KEY).enqueue(new Callback<SearchMovie>() {
            @SuppressWarnings("ConstantConditions")
            @Override
            public void onResponse(@NonNull Call<SearchMovie> call, @NonNull Response<SearchMovie> response) {
                if (response.isSuccessful()) {
                    mMovieList = response.body().Search;
                    mAdapter.addItems(mMovieList);
                    mAdapter.notifyDataSetChanged();
                    mShimmerLayout.stopShimmerAnimation();
                    mShimmerLayout.setVisibility(View.GONE);
                    mRecyclerView.smoothScrollToPosition(0);
                }
            }

            @Override
            public void onFailure(@NonNull Call<SearchMovie> call, @NonNull Throwable t) {
                if (!call.isCanceled()) {
                    t.printStackTrace();
                }
                mShimmerLayout.stopShimmerAnimation();
            }
        });
    }
}

4. Final Result

Now let's look at the result.


app.png


In my example I have a search view. Let's try and search "black panther", once I press enter on the keyboard it will run fetchData(); and inside it I have set the visibility of ShimmerFrameLayout to visible and start its animation.


load.png



Once 'fetchData();` response is successful and data has been added into RecyclerViewAdapter, ShimmerFrameLayout visibility will be set to gone and animation will be stop.


final.png

Documentation



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

@steven.tjg, Contribution to open source project, I like you and upvote.

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Hey @steven.tjg I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Congratulations @steven.tjg! You received a personal award!

1 Year on Steemit

Click here to view your Board

Do not miss the last post from @steemitboard:

Christmas Challenge - The party continues

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @steven.tjg! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!