- Notifications
You must be signed in to change notification settings - Fork10
Memory efficient, simple yet highly customizable shimmer effect for Android.
License
rnpy/ShimmerLayout
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Simple, memory efficient and high performance Shimmer Layout for Android.
ShimmerLayout
can be used to create a shimmer effect to your Android apps loading states (similar to Facebook).
As loading states should be as fast and seamless as possible, this library leaves as much resources as possible for you to do the real work behind, by focusing on:
- memory efficiency: contrary to other similar libraries that usually work using multiple large bitmaps, this librarydoes not use a single bitmap or large object, making its memory footprint negligible.
- performance: on top of avoiding large bitmap manipulation, rendering of each shimmer effect frame is done usingone single native operation, making its impact on CPU and GPU usage as low as possible.
- simplicity:
View.setVisibility()
is all you need to control this layout. - lightweight: just over 150 methods and around 20Kb,before proguard does its magic.
ShimmerLayout
also offers a unique feature allowing better rendering on complex layouts (especially when used inRecyclerView
as a placeholder for eachViewHolder
): multipleShimmerLayout
can easily be synchronized together to use the exact same animation.
Despite its simplicity and small size,ShimmerLayout
can still be configured for much more complex use cases thanks to a few optional parameters.
Simple use case with default animation, in aRecyclerView
allowing scrolling while elements are still loading:
And a more complex loading screen usingShimmerLayout
to create a color-changing, rotating shimmer effect on some animated views (in less than 20 lines!):
Originally inspired byFacebook Shimmer for Android andSupercharge ShimmerLayout.
Use gradle to get latest version from bintray jCenter:
repositories { maven { url"https://jcenter.bintray.com" } }implementation'xyz.peridy.shimmer:shimmerlayout:1.1'
Wrap the layout you want to animate inside aShimmerLayout
. It is recommended to define a layout that looks like the content you're going to display:
<xyz.peridy.shimmerlayout.ShimmerLayoutandroid:id="@+id/shimmer_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"> <LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:padding="16dp"> <Viewandroid:layout_width="42dp"android:layout_height="42dp"android:background="@color/shimmerBackground"/> <LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"> <Viewandroid:layout_width="152dp"android:layout_height="14dp"android:layout_marginLeft="8dp"android:layout_marginStart="8dp"android:background="@color/shimmerBackground"/> <Viewandroid:layout_width="122dp"android:layout_height="14dp"android:layout_marginLeft="8dp"android:layout_marginStart="8dp"android:layout_marginTop="4dp"android:background="@color/shimmerBackground"/> </LinearLayout> </LinearLayout></xyz.peridy.shimmerlayout.ShimmerLayout>
For the most basic usage, that's all you need. When this layout is visible, it will start animating. It will automatically stop or start again when its visibility change, since it's intended to be a loading placeholder, you're probably already doing this anyway.
ShimmerLayout
should work on any view, but remember this is only a loading indicator, and keep things simple. Animated content can also be used in some cases, just make sure to make it as lightweight as possible and use native Android animations (seeEvaluatorsDemoActivity
):
By default,ShimmerLayout
will create an effect based those parameters
- shimmerAngle: shadow angle
- shimmerWidth: total width of shadow
- shimmerCenterWidth: width of solid color in the center of shadow
- shimmerDuration: duration in ms
- shimmerColor: color
All these can also be set directly in xml layout:
<xyz.peridy.shimmerlayout.ShimmerLayoutxmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="wrap_content"android:layout_height="wrap_content"app:shimmer_center_width="10dp"app:shimmer_width="20dp"app:shimmer_angle="30"app:shimmer_duration="250"app:shimmer_color="#FF0000">
Groups allow multipleShimmerLayout
to be synchronized with each other. It is highly recommended to use a group when using multipleShimmerLayout
on the same screen.
Without Group, if newShimmerLayout
are added after animation is started (scrolling down aRecyclerView
for example), you can end up in cases like this, which would make your designers cry:
With a group, newly added views are synchronized with any existing one, making designers much happier:
To set a group, simply create aShimmerGroup
object in code, and pass it to allShimmerLayout
you want synchronised:
val myShimmerGroup=ShimmerGroup()findViewById<ShimmerLayout>(R.id.shimmer_layout_1).shimmerGroup= myShimmerGroupfindViewById<ShimmerLayout>(R.id.shimmer_layout_2).shimmerGroup= myShimmerGroup
For the most common use (inRecyclerView
), it is recommended to define the group in the adapter, and pass it to all ViewHolders (see demo app).
ATimeInterpolator can be provided to modify the rate of change of the animation. For example, to have the shimmer accelerate then decelerate, simply use:
shimmerLayout.timeInterpolator=AccelerateDecelerateInterpolator()
ShimmerLayout
draws the effect on every frame using one singledrawPaint operation.ShimmerLayout
provides 3 ways to customize animation thoughEvaluator
classes. Each of these expose a method that is called on each frame to customize the effect, so be mindful of performance when implementing them.
For example, this customizes the effect to use a color-changing radial gradient instead of the default linear gradient, growing and shrinking from the center of the view instead of using a translation from left to right:
matrixEvaluator=nulltimeInterpolator=CycleInterpolator(1f)setShaderEvaluator { fraction->val radius=Math.abs(fraction)* width+1RadialGradient(width/2f, height/2f, radius, intArrayOf(Color.BLACK,Color.TRANSPARENT),null,Shader.TileMode.CLAMP)}colorEvaluator=object:ShimmerLayout.Evaluator<Int> {val evaluator=ArgbEvaluator()val colours= arrayOf("#B00000","#00B000","#0000B0").map {Color.parseColor(it) }val count= colours.sizeoverridefunevaluate(fraction:Float):Int {val localFraction= (1+ fraction)/2// CycleInterpolator means fraction ranges from -1 to 1val arrayPosition= (localFraction* count).toInt()% countval offset= localFraction* count%1.0freturn evaluator.evaluate(offset, colours[arrayPosition], colours[(arrayPosition+1)% count])asInt }}
And now your designers can cry again with this result:
The shader is used to create the shadow effect. Providing one allows you to customize the shader to use for each animation frame.
See example above for use of aRadialGradient
The color used to tint the shadow effect. By default,ShimmerLayout
will use theshimmerColor
attribute to tint the effect. Providing anEvaluator
allows you to define the color to use for each animation frame.
See example above for use ofArgbEvaluator
to alternate between multiple colours.
Default Matrix uses a translation from left to right, this can be modified by providing a customEvaluator<Matrix>
. For example, this replaces the translation with a rotation (seeEvaluatorsDemoActivity
for an example using this):
val matrix=Matrix()setMatrixEvaluator { fraction-> matrix.apply { setRotate(fraction*360) }}
BSD License
Copyright (c) 2017, Romain PeridyAll rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the followingdisclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the followingdisclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AREDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ORSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OFTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
About
Memory efficient, simple yet highly customizable shimmer effect for Android.