diff --git a/FACEBOOK_LICENSE.md b/FACEBOOK_LICENSE.md
deleted file mode 100644
index 15d4ea1..0000000
--- a/FACEBOOK_LICENSE.md
+++ /dev/null
@@ -1,13 +0,0 @@
-BSD License
-
-For shimmer-android software
-
-Copyright (c) 2015, Facebook, Inc. All 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 following disclaimer.
-
-Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 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 ARE DISCLAIMED. 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 OR SERVICES; 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/README.md b/README.md
index 094ef46..2e6cddf 100644
--- a/README.md
+++ b/README.md
@@ -11,21 +11,42 @@ A custom recycler view with shimmer views to indicate that views are loading. Th
Demo Screen
-------
+------
+
+There are two kinds of shimmer animation which you can see here:
+
+1. This type of shimmer effect uses the whole ViewHolder item to animate on.
| List Demo | Grid Demo |
| ---------------------------- | ----------------------------- |
| | |
+2. Here the shimmer effect only applied on for those views which background color is nontransparent.
+
+| List Demo | Grid Demo |
+| ---------------------------- | ----------------------------- |
+| | |
+
+
+### Shimmer effect types
+
+1. As you can see the first demo examples show that the whole ViewHolder item is animated. To achieve the desired effect, the children of the ShimmerLayout should have a nontransparent background.
+2. You can achieve the second kind of shimmer effect by adding only one ViewGroup child to the ShimmerLayout with a transparent background. This ViewGroup will have the other views with nontransparent backgrounds on which the effect will be seen.
+
+ You may wonder how can you add background to the root view of the ViewHolder, if you do not have direct access to the ShimmerLayout and the only child has a nontransparent background. The solution for this is to use the `shimmer_demo_view_holder_item_background` attribute.
+
### Attributes and Methods
Following are the attributes and methods to initialise the demo views.
| XML Attributes | Java Methods | Explanation |
| ------------- | ------------ | ----------- |
-|```app:demo_child_count``` | ```setDemoChildCount(int)``` | Integer value that sets the number of demo views should be present in shimmer adapter |
-|```app:demo_layout``` | ```setDemoLayoutReference(int)``` | Layout reference to your demo view. Define your my_demo_view.xml and refer the layout reference here. |
-|```app:demo_layout_manager_type``` | ```setDemoLayoutManager(LayoutManagerType)``` | Layout manager of demo view. Can be one among linear_veritical or linear_horizontal or grid. |
+|```app:shimmer_demo_child_count``` | ```setDemoChildCount(int)``` | Integer value that sets the number of demo views should be present in shimmer adapter. |
+|```app:shimmer_demo_layout``` | ```setDemoLayoutReference(int)``` | Layout reference to your demo view. Define your my_demo_view.xml and refer the layout reference here. |
+|```app:shimmer_demo_layout_manager_type``` | ```setDemoLayoutManager(LayoutManagerType)``` | Layout manager of demo view. Can be one among linear_vertical or linear_horizontal or grid. |
+|```app:shimmer_demo_shimmer_color``` | ``` - ``` | Color reference or value. It can be used to change the color of the shimmer line. |
+|```app:shimmer_demo_angle``` | ``` - ``` | Integer value between 0 and 30 which can modify the angle of the shimmer line. The default value is zero. |
+|```app:shimmer_demo_view_holder_item_background``` | ``` - ``` | Color or an xml drawable for the ViewHolder background if you want to achieve the second type of shimmer effect. |
@@ -44,6 +65,7 @@ Define your xml as:
app:demo_grid_child_count="2"
app:demo_layout="@layout/layout_demo_grid"
app:demo_layout_manager_type="grid"
+ app:shimmer_demo_angle="20"
/>
```
@@ -76,17 +98,17 @@ Developed By
* Harish Sridharan -
-Acknowledgements
+Used libraries
----------------
-* Facebook for Shimmer Android which lies as a base for this repo.
+* ShimmerLayout: the library which achieves the shimmer effect in a memory efficient way.
License
--------
The repo is released under following licenses
Apache License for ShimmerRecycler
-BSD License for Facebook's Shimmer-Android
+Apache License for ShimmerLayout
diff --git a/app/src/main/java/com/cooltechworks/sample/DemoActivity.java b/app/src/main/java/com/cooltechworks/sample/DemoActivity.java
index c29b90c..8a4909d 100644
--- a/app/src/main/java/com/cooltechworks/sample/DemoActivity.java
+++ b/app/src/main/java/com/cooltechworks/sample/DemoActivity.java
@@ -18,12 +18,11 @@
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import com.cooltechworks.sample.adapters.CardAdapter;
import com.cooltechworks.sample.utils.BaseUtils;
+import com.cooltechworks.sample.utils.DemoConfiguration;
import com.cooltechworks.views.shimmer.ShimmerRecyclerView;
public class DemoActivity extends AppCompatActivity {
@@ -37,26 +36,21 @@ public class DemoActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- int type = getType();
+ final int type = getType();
RecyclerView.LayoutManager layoutManager;
- if (type == BaseUtils.TYPE_LIST) {
- setTheme(R.style.AppTheme);
- setContentView(R.layout.activity_list);
- layoutManager = new LinearLayoutManager(this);
- setTitle(R.string.ab_list_title);
-
- } else {
- setTheme(R.style.AppThemeGrid);
- setContentView(R.layout.activity_grid);
- layoutManager = new GridLayoutManager(this, 2);
- setTitle(R.string.ab_grid_title);
-
- }
+ final DemoConfiguration demoConfiguration = BaseUtils.getDemoConfiguration(type, this);
+ setTheme(demoConfiguration.getStyleResource());
+ setContentView(demoConfiguration.getLayoutResource());
+ layoutManager = demoConfiguration.getLayoutManager();
+ setTitle(demoConfiguration.getTitleResource());
shimmerRecycler = (ShimmerRecyclerView) findViewById(R.id.shimmer_recycler_view);
+ if (demoConfiguration.getItemDecoration() != null) {
+ shimmerRecycler.addItemDecoration(demoConfiguration.getItemDecoration());
+ }
mAdapter = new CardAdapter();
mAdapter.setType(type);
@@ -70,8 +64,7 @@ protected void onCreate(Bundle savedInstanceState) {
public void run() {
loadCards();
}
- }, 2000);
-
+ }, 3000);
}
private void loadCards() {
diff --git a/app/src/main/java/com/cooltechworks/sample/MainActivity.java b/app/src/main/java/com/cooltechworks/sample/MainActivity.java
index 0e3a66d..931d549 100644
--- a/app/src/main/java/com/cooltechworks/sample/MainActivity.java
+++ b/app/src/main/java/com/cooltechworks/sample/MainActivity.java
@@ -20,6 +20,7 @@
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
+import android.widget.Button;
import com.cooltechworks.sample.utils.BaseUtils;
@@ -29,17 +30,32 @@ public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+
+ final Button firstListDemoButton = (Button) findViewById(R.id.list_demo_button);
+ final Button firstGridDemoButton = (Button) findViewById(R.id.grid_demo_button);
+
+ createClickListener(firstListDemoButton, BaseUtils.TYPE_LIST);
+ createClickListener(firstGridDemoButton, BaseUtils.TYPE_GRID);
+
+ final Button secondListDemoButton = (Button) findViewById(R.id.list_second_demo_button);
+ final Button secondGridDemoButton = (Button) findViewById(R.id.grid_second_demo_button);
+
+ createClickListener(secondListDemoButton, BaseUtils.TYPE_SECOND_LIST);
+ createClickListener(secondGridDemoButton, BaseUtils.TYPE_SECOND_GRID);
}
- public void listButtonClick(View v) {
- Intent intent = new Intent(this, DemoActivity.class);
- intent.putExtra(DemoActivity.EXTRA_TYPE, BaseUtils.TYPE_LIST);
- startActivity(intent);
+ private void createClickListener(Button button, final int demoType) {
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ startDemo(demoType);
+ }
+ });
}
- public void gridButtonClick(View v) {
+ private void startDemo(int demoType) {
Intent intent = new Intent(this, DemoActivity.class);
- intent.putExtra(DemoActivity.EXTRA_TYPE, BaseUtils.TYPE_GRID);
+ intent.putExtra(DemoActivity.EXTRA_TYPE, demoType);
startActivity(intent);
}
}
diff --git a/app/src/main/java/com/cooltechworks/sample/utils/BaseUtils.java b/app/src/main/java/com/cooltechworks/sample/utils/BaseUtils.java
index b9b6f3a..066812d 100644
--- a/app/src/main/java/com/cooltechworks/sample/utils/BaseUtils.java
+++ b/app/src/main/java/com/cooltechworks/sample/utils/BaseUtils.java
@@ -15,10 +15,14 @@
*/
package com.cooltechworks.sample.utils;
+import android.content.Context;
import android.content.res.Resources;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.LinearLayoutManager;
import com.cooltechworks.sample.R;
import com.cooltechworks.sample.models.ItemCard;
+import com.cooltechworks.sample.utils.view.CardPaddingItemDecoration;
/**
* Created by sharish on 27/12/16.
@@ -26,7 +30,10 @@
public class BaseUtils {
- public static final int TYPE_LIST = 0, TYPE_GRID = 1;
+ public static final int TYPE_LIST = 0;
+ public static final int TYPE_GRID = 1;
+ public static final int TYPE_SECOND_LIST = 2;
+ public static final int TYPE_SECOND_GRID = 3;
private static ItemCard[] getListCards(Resources resources) {
@@ -115,6 +122,61 @@ private static ItemCard[] getGridCards(Resources resources) {
}
public static ItemCard[] getCards(Resources resources, int type) {
- return type == TYPE_LIST ? getListCards(resources) : getGridCards(resources);
+ ItemCard[] itemCards;
+
+ switch (type) {
+ case TYPE_LIST:
+ case TYPE_SECOND_LIST:
+ itemCards = getListCards(resources);
+ break;
+ case TYPE_GRID:
+ case TYPE_SECOND_GRID:
+ itemCards = getGridCards(resources);
+ break;
+ default:
+ itemCards = null;
+ }
+
+ return itemCards;
+ }
+
+ public static DemoConfiguration getDemoConfiguration(int configurationType, Context context) {
+ DemoConfiguration demoConfiguration;
+
+ switch (configurationType) {
+ case TYPE_LIST:
+ demoConfiguration = new DemoConfiguration();
+ demoConfiguration.setStyleResource(R.style.AppTheme);
+ demoConfiguration.setLayoutResource(R.layout.activity_list);
+ demoConfiguration.setLayoutManager(new LinearLayoutManager(context));
+ demoConfiguration.setTitleResource(R.string.ab_list_title);
+ break;
+ case TYPE_GRID:
+ demoConfiguration = new DemoConfiguration();
+ demoConfiguration.setStyleResource(R.style.AppThemeGrid);
+ demoConfiguration.setLayoutResource(R.layout.activity_grid);
+ demoConfiguration.setLayoutManager(new GridLayoutManager(context, 2));
+ demoConfiguration.setTitleResource(R.string.ab_grid_title);
+ break;
+ case TYPE_SECOND_LIST:
+ demoConfiguration = new DemoConfiguration();
+ demoConfiguration.setStyleResource(R.style.AppTheme);
+ demoConfiguration.setLayoutResource(R.layout.activity_second_list);
+ demoConfiguration.setLayoutManager(new LinearLayoutManager(context));
+ demoConfiguration.setTitleResource(R.string.ab_list_title);
+ demoConfiguration.setItemDecoration(new CardPaddingItemDecoration(context));
+ break;
+ case TYPE_SECOND_GRID:
+ demoConfiguration = new DemoConfiguration();
+ demoConfiguration.setStyleResource(R.style.AppThemeGrid);
+ demoConfiguration.setLayoutResource(R.layout.activity_second_grid);
+ demoConfiguration.setLayoutManager(new GridLayoutManager(context, 2));
+ demoConfiguration.setTitleResource(R.string.ab_grid_title);
+ break;
+ default:
+ demoConfiguration = null;
+ }
+
+ return demoConfiguration;
}
}
diff --git a/app/src/main/java/com/cooltechworks/sample/utils/DemoConfiguration.java b/app/src/main/java/com/cooltechworks/sample/utils/DemoConfiguration.java
new file mode 100644
index 0000000..8e34d37
--- /dev/null
+++ b/app/src/main/java/com/cooltechworks/sample/utils/DemoConfiguration.java
@@ -0,0 +1,62 @@
+package com.cooltechworks.sample.utils;
+
+
+import android.support.annotation.LayoutRes;
+import android.support.annotation.StringRes;
+import android.support.annotation.StyleRes;
+import android.support.v7.widget.RecyclerView;
+
+public class DemoConfiguration {
+ @StyleRes
+ private int styleResource;
+
+ @LayoutRes
+ private int layoutResource;
+
+ @StringRes
+ private int titleResource;
+
+ private RecyclerView.LayoutManager layoutManager;
+
+ private RecyclerView.ItemDecoration itemDecoration;
+
+ public RecyclerView.ItemDecoration getItemDecoration() {
+ return itemDecoration;
+ }
+
+ public void setItemDecoration(RecyclerView.ItemDecoration itemDecoration) {
+ this.itemDecoration = itemDecoration;
+ }
+
+ public int getStyleResource() {
+ return styleResource;
+ }
+
+ public void setStyleResource(int styleResource) {
+ this.styleResource = styleResource;
+ }
+
+ public int getLayoutResource() {
+ return layoutResource;
+ }
+
+ public void setLayoutResource(int layoutResource) {
+ this.layoutResource = layoutResource;
+ }
+
+ public int getTitleResource() {
+ return titleResource;
+ }
+
+ public void setTitleResource(int titleResource) {
+ this.titleResource = titleResource;
+ }
+
+ public RecyclerView.LayoutManager getLayoutManager() {
+ return layoutManager;
+ }
+
+ public void setLayoutManager(RecyclerView.LayoutManager layoutManager) {
+ this.layoutManager = layoutManager;
+ }
+}
diff --git a/app/src/main/java/com/cooltechworks/sample/utils/view/CardPaddingItemDecoration.java b/app/src/main/java/com/cooltechworks/sample/utils/view/CardPaddingItemDecoration.java
new file mode 100644
index 0000000..ccf58f7
--- /dev/null
+++ b/app/src/main/java/com/cooltechworks/sample/utils/view/CardPaddingItemDecoration.java
@@ -0,0 +1,22 @@
+package com.cooltechworks.sample.utils.view;
+
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView;
+import android.util.TypedValue;
+import android.view.View;
+
+public class CardPaddingItemDecoration extends RecyclerView.ItemDecoration {
+
+ private int paddingBetweenItems;
+
+ public CardPaddingItemDecoration(Context context) {
+ this.paddingBetweenItems = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, context.getResources().getDisplayMetrics());
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+ outRect.set(0, 0, 0, paddingBetweenItems);
+ }
+}
diff --git a/app/src/main/java/com/cooltechworks/sample/viewholders/ItemHolder.java b/app/src/main/java/com/cooltechworks/sample/viewholders/ItemHolder.java
index da644d7..e3cd2de 100644
--- a/app/src/main/java/com/cooltechworks/sample/viewholders/ItemHolder.java
+++ b/app/src/main/java/com/cooltechworks/sample/viewholders/ItemHolder.java
@@ -25,7 +25,11 @@
import com.bumptech.glide.Glide;
import com.cooltechworks.sample.R;
import com.cooltechworks.sample.models.ItemCard;
-import com.cooltechworks.sample.utils.BaseUtils;
+
+import static com.cooltechworks.sample.utils.BaseUtils.TYPE_GRID;
+import static com.cooltechworks.sample.utils.BaseUtils.TYPE_LIST;
+import static com.cooltechworks.sample.utils.BaseUtils.TYPE_SECOND_GRID;
+import static com.cooltechworks.sample.utils.BaseUtils.TYPE_SECOND_LIST;
/**
* Created by sharish on 27/12/16.
@@ -40,7 +44,7 @@ public class ItemHolder extends RecyclerView.ViewHolder {
public static ItemHolder newInstance(ViewGroup container, int type) {
- View root = LayoutInflater.from(container.getContext()).inflate(type == BaseUtils.TYPE_LIST ? R.layout.layout_news_card : R.layout.layout_ecom_item, container, false);
+ View root = LayoutInflater.from(container.getContext()).inflate(getLayoutResourceId(type), container, false);
return new ItemHolder(root);
}
@@ -61,4 +65,24 @@ public void bind(ItemCard card) {
Glide.with(itemView.getContext()).load(card.getThumbnailUrl()).into(mThumbnailView);
}
+
+ private static int getLayoutResourceId(int type) {
+ int selectedLayoutResource;
+ switch (type) {
+ case TYPE_LIST:
+ selectedLayoutResource = R.layout.layout_news_card;
+ break;
+ case TYPE_SECOND_LIST:
+ selectedLayoutResource = R.layout.layout_second_news_card;
+ break;
+ case TYPE_GRID:
+ case TYPE_SECOND_GRID:
+ selectedLayoutResource = R.layout.layout_ecom_item;
+ break;
+ default:
+ selectedLayoutResource = 0;
+ }
+
+ return selectedLayoutResource;
+ }
}
diff --git a/app/src/main/res/layout/activity_grid.xml b/app/src/main/res/layout/activity_grid.xml
index 8518931..b989ca8 100644
--- a/app/src/main/res/layout/activity_grid.xml
+++ b/app/src/main/res/layout/activity_grid.xml
@@ -35,6 +35,7 @@ limitations under the License.
app:shimmer_demo_child_count="10"
app:shimmer_demo_grid_child_count="2"
app:shimmer_demo_layout="@layout/layout_demo_grid"
+ app:shimmer_demo_shimmer_color="#21ffffff"
app:shimmer_demo_layout_manager_type="grid"
/>
diff --git a/app/src/main/res/layout/activity_list.xml b/app/src/main/res/layout/activity_list.xml
index 1dbc634..9b4ce54 100644
--- a/app/src/main/res/layout/activity_list.xml
+++ b/app/src/main/res/layout/activity_list.xml
@@ -34,6 +34,7 @@ limitations under the License.
android:paddingTop="10dp"
app:shimmer_demo_child_count="10"
app:shimmer_demo_layout="@layout/layout_demo"
+ app:shimmer_demo_shimmer_color="#73ffffff"
/>
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index f42bea9..9356719 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -17,38 +17,56 @@ limitations under the License.
-->
-
+
+
- />
+
+ android:text="@string/second_grid_demo"/>
+
-
+
diff --git a/app/src/main/res/layout/activity_second_grid.xml b/app/src/main/res/layout/activity_second_grid.xml
new file mode 100644
index 0000000..ab38379
--- /dev/null
+++ b/app/src/main/res/layout/activity_second_grid.xml
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_second_list.xml b/app/src/main/res/layout/activity_second_list.xml
new file mode 100644
index 0000000..1831dfd
--- /dev/null
+++ b/app/src/main/res/layout/activity_second_list.xml
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_second_demo.xml b/app/src/main/res/layout/layout_second_demo.xml
new file mode 100644
index 0000000..f666d60
--- /dev/null
+++ b/app/src/main/res/layout/layout_second_demo.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_second_demo_grid.xml b/app/src/main/res/layout/layout_second_demo_grid.xml
new file mode 100644
index 0000000..0d1f232
--- /dev/null
+++ b/app/src/main/res/layout/layout_second_demo_grid.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_second_news_card.xml b/app/src/main/res/layout/layout_second_news_card.xml
new file mode 100644
index 0000000..c11a418
--- /dev/null
+++ b/app/src/main/res/layout/layout_second_news_card.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3e94821..010b7cf 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -17,9 +17,10 @@ limitations under the License.
-->
-
ShimmingRecyclerViewList DemoGrid Demo
+ Second List Demo
+ Second Grid Demo
\ No newline at end of file
diff --git a/screenshots/second_grid_demo.gif b/screenshots/second_grid_demo.gif
new file mode 100644
index 0000000..e9d9954
Binary files /dev/null and b/screenshots/second_grid_demo.gif differ
diff --git a/screenshots/second_list_demo.gif b/screenshots/second_list_demo.gif
new file mode 100644
index 0000000..efb1d39
Binary files /dev/null and b/screenshots/second_list_demo.gif differ
diff --git a/shimmer/build.gradle b/shimmer/build.gradle
index 478c42a..4be0a57 100644
--- a/shimmer/build.gradle
+++ b/shimmer/build.gradle
@@ -22,4 +22,5 @@ android {
dependencies {
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:appcompat-v7:25.3.1'
+ compile 'io.supercharge:shimmerlayout:1.0.1'
}
diff --git a/shimmer/src/main/AndroidManifest.xml b/shimmer/src/main/AndroidManifest.xml
index 2c03a40..67cf897 100644
--- a/shimmer/src/main/AndroidManifest.xml
+++ b/shimmer/src/main/AndroidManifest.xml
@@ -15,16 +15,8 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
-
+
-
-
-
-
+
diff --git a/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerAdapter.java b/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerAdapter.java
index 1e2e801..26a2f7b 100644
--- a/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerAdapter.java
+++ b/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerAdapter.java
@@ -17,12 +17,11 @@
package com.cooltechworks.views.shimmer;
+import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
-import com.cooltechworks.views.shimmer.ShimmerViewHolder;
-
/**
* Created by sharish on 22/11/16.
*/
@@ -31,7 +30,9 @@ public class ShimmerAdapter extends RecyclerView.Adapter {
private int mItemCount = 10;
private int mLayoutReference = R.layout.layout_sample_view;
-
+ private int mShimmerAngle;
+ private int mShimmerColor;
+ private Drawable mShimmerItemBackground;
public void setMinItemCount(int itemCount) {
mItemCount = itemCount;
@@ -39,9 +40,14 @@ public void setMinItemCount(int itemCount) {
@Override
public ShimmerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
- return new ShimmerViewHolder(inflater, parent, mLayoutReference);
+
+ ShimmerViewHolder shimmerViewHolder = new ShimmerViewHolder(inflater, parent, mLayoutReference);
+ shimmerViewHolder.setShimmerColor(mShimmerColor);
+ shimmerViewHolder.setShimmerAngle(mShimmerAngle);
+ shimmerViewHolder.setShimmerViewHolderBackground(mShimmerItemBackground);
+
+ return shimmerViewHolder;
}
@Override
@@ -54,6 +60,18 @@ public int getItemCount() {
return mItemCount;
}
+ public void setShimmerAngle(int shimmerAngle) {
+ this.mShimmerAngle = shimmerAngle;
+ }
+
+ public void setShimmerColor(int shimmerColor) {
+ this.mShimmerColor = shimmerColor;
+ }
+
+ public void setShimmerItemBackground(Drawable shimmerItemBackground) {
+ this.mShimmerItemBackground = shimmerItemBackground;
+ }
+
public void setLayoutReference(int layoutReference) {
this.mLayoutReference = layoutReference;
}
diff --git a/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerRecyclerView.java b/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerRecyclerView.java
index 6d9cdd5..56c0150 100644
--- a/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerRecyclerView.java
+++ b/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerRecyclerView.java
@@ -18,6 +18,8 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
@@ -62,9 +64,13 @@ public ShimmerRecyclerView(Context context, @Nullable AttributeSet attrs, int de
}
private void init(AttributeSet attrs) {
-
mShimmerAdapter = new ShimmerAdapter();
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ShimmerRecyclerView, 0, 0);
+
+ int mShimmerAngle;
+ int mShimmerColor;
+ Drawable mShimmerItemBackground;
+
try {
if (a.hasValue(R.styleable.ShimmerRecyclerView_shimmer_demo_layout)) {
setDemoLayoutReference(a.getResourceId(R.styleable.ShimmerRecyclerView_shimmer_demo_layout, R.layout.layout_sample_view));
@@ -95,13 +101,18 @@ private void init(AttributeSet attrs) {
setGridChildCount(a.getInteger(R.styleable.ShimmerRecyclerView_shimmer_demo_grid_child_count, 2));
}
+ mShimmerAngle = a.getInteger(R.styleable.ShimmerRecyclerView_shimmer_demo_angle, 0);
+ mShimmerColor = a.getColor(R.styleable.ShimmerRecyclerView_shimmer_demo_shimmer_color, getColor(R.color.default_shimmer_color));
+ mShimmerItemBackground = a.getDrawable(R.styleable.ShimmerRecyclerView_shimmer_demo_view_holder_item_background);
} finally {
a.recycle();
}
- showShimmerAdapter();
-
+ mShimmerAdapter.setShimmerAngle(mShimmerAngle);
+ mShimmerAdapter.setShimmerColor(mShimmerColor);
+ mShimmerAdapter.setShimmerItemBackground(mShimmerItemBackground);
+ showShimmerAdapter();
}
/**
@@ -233,4 +244,12 @@ public void setDemoLayoutReference(int mLayoutReference) {
this.mLayoutReference = mLayoutReference;
mShimmerAdapter.setLayoutReference(getLayoutReference());
}
+
+ private int getColor(int id) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ return getContext().getColor(id);
+ } else {
+ return getResources().getColor(id);
+ }
+ }
}
diff --git a/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerViewHolder.java b/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerViewHolder.java
index 4dea2d2..d8e513c 100644
--- a/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerViewHolder.java
+++ b/shimmer/src/main/java/com/cooltechworks/views/shimmer/ShimmerViewHolder.java
@@ -17,12 +17,14 @@
package com.cooltechworks.views.shimmer;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
-import com.facebook.shimmer.ShimmerFrameLayout;
+import io.supercharge.shimmerlayout.ShimmerLayout;
+
/**
* Created by sharish on 22/11/16.
@@ -30,22 +32,42 @@
public class ShimmerViewHolder extends RecyclerView.ViewHolder {
+ private ShimmerLayout mShimmerLayout;
+
public ShimmerViewHolder(LayoutInflater inflater, ViewGroup parent, int innerViewResId) {
super(inflater.inflate(R.layout.viewholder_shimmer, parent, false));
- ShimmerFrameLayout layout = (ShimmerFrameLayout) itemView;
- layout.setGroup(Integer.toString(innerViewResId));
+ mShimmerLayout = (ShimmerLayout) itemView;
+
+ inflater.inflate(innerViewResId, mShimmerLayout, true);
+ }
+
+ public void setShimmerAngle(int angle) {
+ mShimmerLayout.setShimmerAngle(angle);
+ }
- View innerView = inflater.inflate(innerViewResId, layout, false);
- layout.addView(innerView);
- layout.setAutoStart(false);
+ public void setShimmerColor(int color) {
+ mShimmerLayout.setShimmerColor(color);
+ }
+
+ public void setShimmerViewHolderBackground(Drawable viewHolderBackground) {
+ if (viewHolderBackground != null) {
+ setBackground(viewHolderBackground);
+ }
}
/**
* Binds the view
*/
public void bind() {
-
- ShimmerFrameLayout layout = (ShimmerFrameLayout) itemView;
+ ShimmerLayout layout = (ShimmerLayout) itemView;
layout.startShimmerAnimation();
}
+
+ private void setBackground(Drawable background) {
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
+ mShimmerLayout.setBackground(background);
+ } else {
+ mShimmerLayout.setBackgroundDrawable(background);
+ }
+ }
}
diff --git a/shimmer/src/main/java/com/facebook/shimmer/ShimmerFrameLayout.java b/shimmer/src/main/java/com/facebook/shimmer/ShimmerFrameLayout.java
deleted file mode 100644
index 2045597..0000000
--- a/shimmer/src/main/java/com/facebook/shimmer/ShimmerFrameLayout.java
+++ /dev/null
@@ -1,1080 +0,0 @@
-/**
- * For shimmer-android software
- *
- * Copyright (c) 2015, Facebook, Inc. All 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 following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 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 ARE DISCLAIMED. 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 OR SERVICES;
- * 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package com.facebook.shimmer;
-
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.RadialGradient;
-import android.graphics.Shader;
-import android.support.v4.util.SimpleArrayMap;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-
-import com.cooltechworks.views.shimmer.R;
-
-public class ShimmerFrameLayout extends FrameLayout {
-
- private static final SimpleArrayMap sUnmaskBitmapCache = new SimpleArrayMap<>();
- private static final SimpleArrayMap sMaskBitmapCache = new SimpleArrayMap<>();
- private static final SimpleArrayMap sAnimatingGroupMembers = new SimpleArrayMap<>();
-
- private static class MaskBitmapCacheEntry {
- Bitmap bitmap;
- int maskOffsetX;
- int maskOffsetY;
- }
-
- private static final String TAG = "ShimmerFrameLayout";
- private static final PorterDuffXfermode DST_IN_PORTER_DUFF_XFERMODE = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
-
- // enum specifying the shape of the highlight mask applied to the contained view
- public enum MaskShape {
- LINEAR,
- RADIAL
- }
-
- // enum controlling the angle of the highlight mask animation
- public enum MaskAngle {
- CW_0, // left to right
- CW_90, // top to bottom
- CW_180, // right to left
- CW_270, // bottom to top
- }
-
- // struct storing various mask related parameters, which are used to construct the mask bitmap
- private static class Mask {
-
- public MaskAngle angle;
- public float tilt;
- public float dropoff;
- public int fixedWidth;
- public int fixedHeight;
- public float intensity;
- public float relativeWidth;
- public float relativeHeight;
- public MaskShape shape;
-
- public int maskWidth(int width) {
- return fixedWidth > 0 ? fixedWidth : (int) (width * relativeWidth);
- }
-
- public int maskHeight(int height) {
- return fixedHeight > 0 ? fixedHeight : (int) (height * relativeHeight);
- }
-
- /**
- * Get the array of colors to be distributed along the gradient of the mask bitmap
- *
- * @return An array of black and transparent colors
- */
- public int[] getGradientColors() {
- switch (shape) {
- default:
- case LINEAR:
- return new int[]{Color.TRANSPARENT, Color.BLACK, Color.BLACK, Color.TRANSPARENT};
- case RADIAL:
- return new int[]{Color.BLACK, Color.BLACK, Color.TRANSPARENT};
- }
- }
-
- /**
- * Get the array of relative positions [0..1] of each corresponding color in the colors array
- *
- * @return A array of float values in the [0..1] range
- */
- public float[] getGradientPositions() {
- switch (shape) {
- default:
- case LINEAR:
- return new float[]{
- Math.max((1.0f - intensity - dropoff) / 2, 0.0f),
- Math.max((1.0f - intensity) / 2, 0.0f),
- Math.min((1.0f + intensity) / 2, 1.0f),
- Math.min((1.0f + intensity + dropoff) / 2, 1.0f)};
- case RADIAL:
- return new float[]{
- 0.0f,
- Math.min(intensity, 1.0f),
- Math.min(intensity + dropoff, 1.0f)};
- }
- }
- }
-
- // struct for storing the mask translation animation values
- private static class MaskTranslation {
-
- public int fromX;
- public int fromY;
- public int toX;
- public int toY;
-
- public void set(int fromX, int fromY, int toX, int toY) {
- this.fromX = fromX;
- this.fromY = fromY;
- this.toX = toX;
- this.toY = toY;
- }
- }
-
- private Paint mAlphaPaint;
- private Paint mMaskPaint;
-
- private Mask mMask;
- private MaskTranslation mMaskTranslation;
-
- private Bitmap mRenderMaskBitmap;
- private Bitmap mRenderUnmaskBitmap;
-
- private boolean mAutoStart;
- private int mDuration;
- private int mRepeatCount;
- private int mRepeatDelay;
- private int mRepeatMode;
- private String group = "";
-
- private int mMaskOffsetX;
- private int mMaskOffsetY;
-
- private boolean mAnimationStarted;
- private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener;
-
- protected ValueAnimator mAnimator;
- protected Bitmap mMaskBitmap;
-
- private boolean mUnmaskFromCache;
- private boolean mMaskFromCache;
-
- public ShimmerFrameLayout(Context context) {
- this(context, null, 0);
- }
-
- public ShimmerFrameLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ShimmerFrameLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- setWillNotDraw(false);
-
- mMask = new Mask();
- mAlphaPaint = new Paint();
- mMaskPaint = new Paint();
- mMaskPaint.setAntiAlias(true);
- mMaskPaint.setDither(true);
- mMaskPaint.setFilterBitmap(true);
- mMaskPaint.setXfermode(DST_IN_PORTER_DUFF_XFERMODE);
-
- useDefaults();
-
- if (attrs != null) {
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ShimmerFrameLayout, 0, 0);
- try {
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_auto_start)) {
- setAutoStart(a.getBoolean(R.styleable.ShimmerFrameLayout_shimmer_auto_start, false));
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_base_alpha)) {
- setBaseAlpha(a.getFloat(R.styleable.ShimmerFrameLayout_shimmer_base_alpha, 0));
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_duration)) {
- setDuration(a.getInt(R.styleable.ShimmerFrameLayout_shimmer_duration, 0));
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_repeat_count)) {
- setRepeatCount(a.getInt(R.styleable.ShimmerFrameLayout_shimmer_repeat_count, 0));
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_repeat_delay)) {
- setRepeatDelay(a.getInt(R.styleable.ShimmerFrameLayout_shimmer_repeat_delay, 0));
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_repeat_mode)) {
- setRepeatMode(a.getInt(R.styleable.ShimmerFrameLayout_shimmer_repeat_mode, 0));
- }
-
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_angle)) {
- int angle = a.getInt(R.styleable.ShimmerFrameLayout_shimmer_angle, 0);
- switch (angle) {
- default:
- case 0:
- mMask.angle = MaskAngle.CW_0;
- break;
- case 90:
- mMask.angle = MaskAngle.CW_90;
- break;
- case 180:
- mMask.angle = MaskAngle.CW_180;
- break;
- case 270:
- mMask.angle = MaskAngle.CW_270;
- break;
- }
- }
-
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_shape)) {
- int shape = a.getInt(R.styleable.ShimmerFrameLayout_shimmer_shape, 0);
- switch (shape) {
- default:
- case 0:
- mMask.shape = MaskShape.LINEAR;
- break;
- case 1:
- mMask.shape = MaskShape.RADIAL;
- break;
- }
- }
-
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_dropoff)) {
- mMask.dropoff = a.getFloat(R.styleable.ShimmerFrameLayout_shimmer_dropoff, 0);
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_fixed_width)) {
- mMask.fixedWidth = a.getDimensionPixelSize(R.styleable.ShimmerFrameLayout_shimmer_fixed_width, 0);
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_fixed_height)) {
- mMask.fixedHeight = a.getDimensionPixelSize(R.styleable.ShimmerFrameLayout_shimmer_fixed_height, 0);
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_intensity)) {
- mMask.intensity = a.getFloat(R.styleable.ShimmerFrameLayout_shimmer_intensity, 0);
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_relative_width)) {
- mMask.relativeWidth = a.getFloat(R.styleable.ShimmerFrameLayout_shimmer_relative_width, 0);
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_relative_height)) {
- mMask.relativeHeight = a.getFloat(R.styleable.ShimmerFrameLayout_shimmer_relative_height, 0);
- }
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_tilt)) {
- mMask.tilt = a.getFloat(R.styleable.ShimmerFrameLayout_shimmer_tilt, 0);
- }
-
- if (a.hasValue(R.styleable.ShimmerFrameLayout_shimmer_group)) {
- group = a.getString(R.styleable.ShimmerFrameLayout_shimmer_group);
- }
-
- } finally {
- a.recycle();
- }
- }
- }
-
- /**
- * Resets the layout to its default state. Any parameters that were set or modified will be reverted back to their
- * original value. Also, stops the shimmer animation if it is currently playing.
- */
- public void useDefaults() {
- // Set defaults
- setAutoStart(false);
- setDuration(1000);
- setRepeatCount(ObjectAnimator.INFINITE);
- setRepeatDelay(0);
- setRepeatMode(ObjectAnimator.RESTART);
-
- mMask.angle = MaskAngle.CW_0;
- mMask.shape = MaskShape.LINEAR;
- mMask.dropoff = 0.5f;
- mMask.fixedWidth = 0;
- mMask.fixedHeight = 0;
- mMask.intensity = 0.0f;
- mMask.relativeWidth = 1.0f;
- mMask.relativeHeight = 1.0f;
- mMask.tilt = 20;
-
- mMaskTranslation = new MaskTranslation();
-
- setBaseAlpha(0.3f);
-
- resetAll();
- }
-
- /**
- * Is 'auto start' enabled for this layout. When auto start is enabled, the layout will start animating automatically
- * whenever it is attached to the current window.
- *
- * @return True if 'auto start' is enabled, false otherwise
- */
- public boolean isAutoStart() {
- return mAutoStart;
- }
-
- /**
- * Enable or disable 'auto start' for this layout. When auto start is enabled, the layout will start animating
- * automatically whenever it is attached to the current window.
- *
- * @param autoStart Whether auto start should be enabled or not
- */
- public void setAutoStart(boolean autoStart) {
- mAutoStart = autoStart;
- resetAll();
- }
-
- /**
- * Get the alpha currently used to render the base view i.e. the unhighlighted view over which the highlight is drawn.
- *
- * @return Alpha (opacity) of the base view
- */
- public float getBaseAlpha() {
- return (float) mAlphaPaint.getAlpha() / 0xff;
- }
-
- /**
- * Set the alpha to be used to render the base view i.e. the unhighlighted view over which the highlight is drawn.
- *
- * @param alpha Alpha (opacity) of the base view
- */
- public void setBaseAlpha(float alpha) {
- mAlphaPaint.setAlpha((int) (clamp(0, 1, alpha) * 0xff));
- resetAll();
- }
-
- /**
- * Get the duration of the current animation i.e. the time it takes for the highlight to move from one end
- * of the layout to the other. The default value is 1000 ms.
- *
- * @return Duration of the animation, in milliseconds
- */
- public int getDuration() {
- return mDuration;
- }
-
- /**
- * Set the duration of the animation i.e. the time it will take for the highlight to move from one end of the layout
- * to the other.
- *
- * @param duration Duration of the animation, in milliseconds
- */
- public void setDuration(int duration) {
- mDuration = duration;
- resetAll();
- }
-
- /**
- * Get the number of times of the current animation will repeat. The default value is -1, which means the animation
- * will repeat indefinitely.
- *
- * @return Number of times the current animation will repeat, or -1 for indefinite.
- */
- public int getRepeatCount() {
- return mRepeatCount;
- }
-
- /**
- * Set the number of times the animation should repeat. If the repeat count is 0, the animation stops after reaching
- * the end. If greater than 0, or -1 (for infinite), the repeat mode is taken into account.
- *
- * @param repeatCount Number of times the current animation should repeat, or -1 for indefinite.
- */
- public void setRepeatCount(int repeatCount) {
- mRepeatCount = repeatCount;
- resetAll();
- }
-
- /**
- * Get the delay after which the current animation will repeat. The default value is 0, which means the animation
- * will repeat immediately, unless it has ended.
- *
- * @return Delay after which the current animation will repeat, in milliseconds.
- */
- public int getRepeatDelay() {
- return mRepeatDelay;
- }
-
- /**
- * Set the delay after which the animation repeat, unless it has ended.
- *
- * @param repeatDelay Delay after which the animation should repeat, in milliseconds.
- */
- public void setRepeatDelay(int repeatDelay) {
- mRepeatDelay = repeatDelay;
- resetAll();
- }
-
- /**
- * Get what the current animation will do after reaching the end. One of
- * REVERSE or
- * RESTART
- *
- * @return Repeat mode of the current animation
- */
- public int getRepeatMode() {
- return mRepeatMode;
- }
-
- /**
- * Set what the animation should do after reaching the end. One of
- * REVERSE or
- * RESTART
- *
- * @param repeatMode Repeat mode of the animation
- */
- public void setRepeatMode(int repeatMode) {
- mRepeatMode = repeatMode;
- resetAll();
- }
-
- /**
- * Get the shape of the current animation's highlight mask. One of {@link MaskShape#LINEAR} or
- * {@link MaskShape#RADIAL}
- *
- * @return The shape of the highlight mask
- */
- public MaskShape getMaskShape() {
- return mMask.shape;
- }
-
- /**
- * Set the shape of the animation's highlight mask. One of {@link MaskShape#LINEAR} or {@link MaskShape#RADIAL}
- *
- * @param shape The shape of the highlight mask
- */
- public void setMaskShape(MaskShape shape) {
- mMask.shape = shape;
- resetAll();
- }
-
- /**
- * Get the angle at which the highlight mask is animated. One of:
- *
- *
{@link MaskAngle#CW_0} which animates left to right,
- *
{@link MaskAngle#CW_90} which animates top to bottom,
- *
{@link MaskAngle#CW_180} which animates right to left, or
- *
{@link MaskAngle#CW_270} which animates bottom to top
- *
- *
- * @return The {@link MaskAngle} of the current animation
- */
- public MaskAngle getAngle() {
- return mMask.angle;
- }
-
- /**
- * Set the angle of the highlight mask animation. One of:
- *
- *
{@link MaskAngle#CW_0} which animates left to right,
- *
{@link MaskAngle#CW_90} which animates top to bottom,
- *
{@link MaskAngle#CW_180} which animates right to left, or
- *
{@link MaskAngle#CW_270} which animates bottom to top
- *
- *
- * @param angle The {@link MaskAngle} of the new animation
- */
- public void setAngle(MaskAngle angle) {
- mMask.angle = angle;
- resetAll();
- }
-
- /**
- * Get the dropoff of the current animation's highlight mask. Dropoff controls the size of the fading edge of the
- * highlight.
- *
- * The default value of dropoff is 0.5.
- *
- * @return Dropoff of the highlight mask
- */
- public float getDropoff() {
- return mMask.dropoff;
- }
-
- /**
- * Set the dropoff of the animation's highlight mask, which defines the size of the highlight's fading edge.
- *
- * It is the relative distance from the center at which the highlight mask's opacity is 0 i.e it is fully transparent.
- * For a linear mask, the distance is relative to the center towards the edges. For a radial mask, the distance is
- * relative to the center towards the circumference. So a dropoff of 0.5 on a linear mask will create a band that
- * is half the size of the corresponding edge (depending on the {@link MaskAngle}), centered in the layout.
- *
- * @param dropoff
- */
- public void setDropoff(float dropoff) {
- mMask.dropoff = dropoff;
- resetAll();
- }
-
- /**
- * Get the fixed width of the highlight mask, or 0 if it is not set. By default it is 0.
- *
- * @return The width of the highlight mask if set, in pixels.
- */
- public int getFixedWidth() {
- return mMask.fixedWidth;
- }
-
- /**
- * Set the fixed width of the highlight mask, regardless of the size of the layout.
- *
- * @param fixedWidth The width of the highlight mask in pixels.
- */
- public void setFixedWidth(int fixedWidth) {
- mMask.fixedWidth = fixedWidth;
- resetAll();
- }
-
- /**
- * Get the fixed height of the highlight mask, or 0 if it is not set. By default it is 0.
- *
- * @return The height of the highlight mask if set, in pixels.
- */
- public int getFixedHeight() {
- return mMask.fixedHeight;
- }
-
- /**
- * Set the fixed height of the highlight mask, regardless of the size of the layout.
- *
- * @param fixedHeight The height of the highlight mask in pixels.
- */
- public void setFixedHeight(int fixedHeight) {
- mMask.fixedHeight = fixedHeight;
- resetAll();
- }
-
- /**
- * Get the intensity of the highlight mask, in the [0..1] range. The intensity controls the brightness of the
- * highlight; the higher it is, the greater is the opaque region in the highlight. The default value is 0.
- *
- * @return The intensity of the highlight mask
- */
- public float getIntensity() {
- return mMask.intensity;
- }
-
- /**
- * Set the intensity of the highlight mask, in the [0..1] range.
- *
- * Intensity is the point relative to the center where opacity starts dropping off, so an intensity of 0 would mean
- * that the highlight starts becoming translucent immediately from the center (the spread is controlled by 'dropoff').
- *
- * @param intensity The intensity of the highlight mask.
- */
- public void setIntensity(float intensity) {
- mMask.intensity = intensity;
- resetAll();
- }
-
- /**
- * Get the width of the highlight mask relative to the layout's width. The default is 1.0, meaning that the mask is
- * of the same width as the layout.
- *
- * @return Relative width of the highlight mask.
- */
- public float getRelativeWidth() {
- return mMask.relativeWidth;
- }
-
- /**
- * Set the width of the highlight mask relative to the layout's width, in the [0..1] range.
- *
- * @param relativeWidth Relative width of the highlight mask.
- */
- public void setRelativeWidth(int relativeWidth) {
- mMask.relativeWidth = relativeWidth;
- resetAll();
- }
-
- /**
- * Get the height of the highlight mask relative to the layout's height. The default is 1.0, meaning that the mask is
- * of the same height as the layout.
- *
- * @return Relative height of the highlight mask.
- */
- public float getRelativeHeight() {
- return mMask.relativeHeight;
- }
-
- /**
- * Set the height of the highlight mask relative to the layout's height, in the [0..1] range.
- *
- * @param relativeHeight Relative height of the highlight mask.
- */
- public void setRelativeHeight(int relativeHeight) {
- mMask.relativeHeight = relativeHeight;
- resetAll();
- }
-
- /**
- * Get the group name of this layout. Layouts within same group will share bitmap caches.
- * Shared bitmap cache should be used when layout's content is static and all layouts within a group have same content.
- * The default is "", meaning no shared bitmap cache.
- *
- * @return Layout's group name.
- */
- public String getGroup() {
- return group;
- }
-
- /**
- * Set the group name of this layout. Layouts within same group will share bitmap caches.
- * Shared bitmap cache should be used when layout's content is static and all layouts within a group have same content.
- *
- * @param group Layout's group name.
- */
- public void setGroup(String group) {
- this.group = group;
- resetAll();
- }
-
- /**
- * Get the tilt angle of the highlight, in degrees. The default value is 20.
- *
- * @return The highlight's tilt angle, in degrees.
- */
- public float getTilt() {
- return mMask.tilt;
- }
-
- /**
- * Set the tile angle of the highlight, in degrees.
- *
- * @param tilt The highlight's tilt angle, in degrees.
- */
- public void setTilt(float tilt) {
- mMask.tilt = tilt;
- resetAll();
- }
-
- /**
- * Start the shimmer animation. If the 'auto start' property is set, this method is called automatically when the
- * layout is attached to the current window. Calling this method has no effect if the animation is already playing.
- */
- public void startShimmerAnimation() {
- if (mAnimationStarted) {
- return;
- }
- Animator animator = getShimmerAnimation();
- animator.start();
- mAnimationStarted = true;
-
- registerToCache();
- }
-
- private void registerToCache() {
- if (group == null || group.isEmpty()) {
- return;
- }
- final Integer count = sAnimatingGroupMembers.get(group);
- sAnimatingGroupMembers.put(group, count == null ? 1 : count + 1);
- }
-
- /**
- * Stop the shimmer animation. Calling this method has no effect if the animation hasn't been started yet.
- */
- public void stopShimmerAnimation() {
- if (mAnimator != null) {
- mAnimator.end();
- mAnimator.removeAllUpdateListeners();
- mAnimator.cancel();
- }
- mAnimator = null;
- mAnimationStarted = false;
- resetMaskBitmap();
- resetRenderedView();
-
- unregisterFromCache();
- }
-
- private void unregisterFromCache() {
- if (group == null || group.isEmpty()) {
- return;
- }
- final Integer count = sAnimatingGroupMembers.get(group);
- if (count == null) {
- return;
- }
- if (count > 1) {
- sAnimatingGroupMembers.put(group, count - 1);
- } else {
- sUnmaskBitmapCache.remove(group);
- sMaskBitmapCache.remove(group);
- sAnimatingGroupMembers.remove(group);
- }
- }
-
- /**
- * Whether the shimmer animation is currently underway.
- *
- * @return True if the shimmer animation is playing, false otherwise.
- */
- public boolean isAnimationStarted() {
- return mAnimationStarted;
- }
-
- /**
- * Translate the mask offset horizontally. Used by the animator.
- *
- * @param maskOffsetX Horizontal translation offset of the mask
- */
- private void setMaskOffsetX(int maskOffsetX) {
- if (mMaskOffsetX == maskOffsetX) {
- return;
- }
- mMaskOffsetX = maskOffsetX;
- invalidate();
- }
-
- /**
- * Translate the mask offset vertically. Used by the animator.
- *
- * @param maskOffsetY Vertical translation offset of the mask
- */
- private void setMaskOffsetY(int maskOffsetY) {
- if (mMaskOffsetY == maskOffsetY) {
- return;
- }
- mMaskOffsetY = maskOffsetY;
- invalidate();
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mGlobalLayoutListener == null) {
- mGlobalLayoutListener = getLayoutListener();
- }
- getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
- }
-
- private ViewTreeObserver.OnGlobalLayoutListener getLayoutListener() {
- return new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- boolean animationStarted = mAnimationStarted;
- resetAll();
- if (mAutoStart || animationStarted) {
- startShimmerAnimation();
- }
- }
- };
- }
-
- @Override
- protected void onDetachedFromWindow() {
- stopShimmerAnimation();
- if (mGlobalLayoutListener != null) {
- getViewTreeObserver().removeGlobalOnLayoutListener(mGlobalLayoutListener);
- mGlobalLayoutListener = null;
- }
- super.onDetachedFromWindow();
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- if (!mAnimationStarted || getWidth() <= 0 || getHeight() <= 0) {
- super.dispatchDraw(canvas);
- return;
- }
- dispatchDrawUsingBitmap(canvas);
- }
-
- private static float clamp(float min, float max, float value) {
- return Math.min(max, Math.max(min, value));
- }
-
- /**
- * Draws and masks the children using a Bitmap.
- *
- * @param canvas Canvas that the masked children will end up being drawn to.
- */
- private boolean dispatchDrawUsingBitmap(Canvas canvas) {
- Bitmap unmaskBitmap = tryObtainRenderUnmaskBitmap();
- Bitmap maskBitmap = tryObtainRenderMaskBitmap();
- if (unmaskBitmap == null || maskBitmap == null) {
- return false;
- }
- // First draw a desaturated version
- if (!mUnmaskFromCache) {
- drawUnmasked(new Canvas(unmaskBitmap));
- sUnmaskBitmapCache.put(group, unmaskBitmap);
- }
- canvas.drawBitmap(unmaskBitmap, 0, 0, mAlphaPaint);
-
- // Then draw the masked version
- if (!mMaskFromCache) {
- drawMasked(new Canvas(maskBitmap));
- cacheMaskBitmap(maskBitmap);
- }
- canvas.drawBitmap(maskBitmap, 0, 0, null);
-
- return true;
- }
-
- private void cacheMaskBitmap(Bitmap maskBitmap) {
- MaskBitmapCacheEntry cacheEntry = sMaskBitmapCache.get(group);
- if (cacheEntry == null) {
- cacheEntry = new MaskBitmapCacheEntry();
- }
- cacheEntry.bitmap = maskBitmap;
- cacheEntry.maskOffsetX = mMaskOffsetX;
- cacheEntry.maskOffsetY = mMaskOffsetY;
- sMaskBitmapCache.put(group, cacheEntry);
- }
-
- private Bitmap tryObtainRenderUnmaskBitmap() {
- if (group != null && !group.isEmpty()) {
- final Bitmap unmaskCached = sUnmaskBitmapCache.get(group);
- if (unmaskCached != null && !unmaskCached.isRecycled()) {
- mUnmaskFromCache = true;
- return unmaskCached;
- }
- }
-
- if (mRenderUnmaskBitmap == null) {
- mRenderUnmaskBitmap = tryCreateRenderBitmap();
- }
- mUnmaskFromCache = false;
- return mRenderUnmaskBitmap;
- }
-
-
- private Bitmap tryObtainRenderMaskBitmap() {
- if (group != null && !group.isEmpty()) {
- final MaskBitmapCacheEntry cacheEntry = sMaskBitmapCache.get(group);
- if (cacheEntry != null && cacheEntry.maskOffsetX == mMaskOffsetX &&
- cacheEntry.maskOffsetY == mMaskOffsetY && !cacheEntry.bitmap.isRecycled()) {
- mMaskFromCache = true;
- return cacheEntry.bitmap;
- }
- }
-
- if (mRenderMaskBitmap == null) {
- mRenderMaskBitmap = tryCreateRenderBitmap();
- }
- mMaskFromCache = false;
- return mRenderMaskBitmap;
- }
-
-
- private Bitmap tryCreateRenderBitmap() {
- int width = getWidth();
- int height = getHeight();
- try {
- return createBitmapAndGcIfNecessary(width, height);
- } catch (OutOfMemoryError e) {
- String logMessage = "ShimmerFrameLayout failed to create working bitmap";
- StringBuilder logMessageStringBuilder = new StringBuilder(logMessage);
- logMessageStringBuilder.append(" (width = ");
- logMessageStringBuilder.append(width);
- logMessageStringBuilder.append(", height = ");
- logMessageStringBuilder.append(height);
- logMessageStringBuilder.append(")\n\n");
- for (StackTraceElement stackTraceElement :
- Thread.currentThread().getStackTrace()) {
- logMessageStringBuilder.append(stackTraceElement.toString());
- logMessageStringBuilder.append("\n");
- }
- logMessage = logMessageStringBuilder.toString();
- Log.d(TAG, logMessage);
- }
- return null;
- }
-
- // Draws the children without any mask.
- private void drawUnmasked(Canvas renderCanvas) {
- renderCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
- super.dispatchDraw(renderCanvas);
- }
-
- // Draws the children and masks them on the given Canvas.
- private void drawMasked(Canvas renderCanvas) {
- Bitmap maskBitmap = getMaskBitmap();
- if (maskBitmap == null) {
- return;
- }
-
- renderCanvas.clipRect(
- mMaskOffsetX,
- mMaskOffsetY,
- mMaskOffsetX + maskBitmap.getWidth(),
- mMaskOffsetY + maskBitmap.getHeight());
- renderCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
- super.dispatchDraw(renderCanvas);
-
- renderCanvas.drawBitmap(maskBitmap, mMaskOffsetX, mMaskOffsetY, mMaskPaint);
- }
-
- private void resetAll() {
- stopShimmerAnimation();
- resetMaskBitmap();
- resetRenderedView();
- }
-
- // If a mask bitmap was created, it's recycled and set to null so it will be recreated when needed.
- private void resetMaskBitmap() {
- if (mMaskBitmap != null) {
- mMaskBitmap.recycle();
- mMaskBitmap = null;
- }
- }
-
- // If a working bitmap was created, it's recycled and set to null so it will be recreated when needed.
- private void resetRenderedView() {
- if (mRenderUnmaskBitmap != null) {
- mRenderUnmaskBitmap.recycle();
- mRenderUnmaskBitmap = null;
- }
-
- if (mRenderMaskBitmap != null) {
- mRenderMaskBitmap.recycle();
- mRenderMaskBitmap = null;
- }
- }
-
- // Return the mask bitmap, creating it if necessary.
- private Bitmap getMaskBitmap() {
- if (mMaskBitmap != null) {
- return mMaskBitmap;
- }
-
- int width = mMask.maskWidth(getWidth());
- int height = mMask.maskHeight(getHeight());
-
- mMaskBitmap = createBitmapAndGcIfNecessary(width, height);
- Canvas canvas = new Canvas(mMaskBitmap);
- Shader gradient;
- switch (mMask.shape) {
- default:
- case LINEAR: {
- int x1, y1;
- int x2, y2;
- switch (mMask.angle) {
- default:
- case CW_0:
- x1 = 0;
- y1 = 0;
- x2 = width;
- y2 = 0;
- break;
- case CW_90:
- x1 = 0;
- y1 = 0;
- x2 = 0;
- y2 = height;
- break;
- case CW_180:
- x1 = width;
- y1 = 0;
- x2 = 0;
- y2 = 0;
- break;
- case CW_270:
- x1 = 0;
- y1 = height;
- x2 = 0;
- y2 = 0;
- break;
- }
- gradient =
- new LinearGradient(
- x1, y1,
- x2, y2,
- mMask.getGradientColors(),
- mMask.getGradientPositions(),
- Shader.TileMode.REPEAT);
- break;
- }
- case RADIAL: {
- int x = width / 2;
- int y = height / 2;
- gradient =
- new RadialGradient(
- x,
- y,
- (float) (Math.max(width, height) / Math.sqrt(2)),
- mMask.getGradientColors(),
- mMask.getGradientPositions(),
- Shader.TileMode.REPEAT);
- break;
- }
- }
- canvas.rotate(mMask.tilt, width / 2, height / 2);
- Paint paint = new Paint();
- paint.setShader(gradient);
- // We need to increase the rect size to account for the tilt
- int padding = (int) (Math.sqrt(2) * Math.max(width, height)) / 2;
- canvas.drawRect(-padding, -padding, width + padding, height + padding, paint);
-
- return mMaskBitmap;
- }
-
- // Get the shimmer Animator
- // object, which is responsible for driving the highlight mask animation.
- private Animator getShimmerAnimation() {
- if (mAnimator != null) {
- return mAnimator;
- }
- int width = getWidth();
- int height = getHeight();
- switch (mMask.shape) {
- default:
- case LINEAR:
- switch (mMask.angle) {
- default:
- case CW_0:
- mMaskTranslation.set(-width, 0, width, 0);
- break;
- case CW_90:
- mMaskTranslation.set(0, -height, 0, height);
- break;
- case CW_180:
- mMaskTranslation.set(width, 0, -width, 0);
- break;
- case CW_270:
- mMaskTranslation.set(0, height, 0, -height);
- break;
- }
- }
- mAnimator = ValueAnimator.ofFloat(0.0f, 1.0f + (float) mRepeatDelay / mDuration);
- mAnimator.setDuration(mDuration + mRepeatDelay);
- mAnimator.setRepeatCount(mRepeatCount);
- mAnimator.setRepeatMode(mRepeatMode);
- mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float value = Math.max(0.0f, Math.min(1.0f, (Float) animation.getAnimatedValue()));
- setMaskOffsetX((int) (mMaskTranslation.fromX * (1 - value) + mMaskTranslation.toX * value));
- setMaskOffsetY((int) (mMaskTranslation.fromY * (1 - value) + mMaskTranslation.toY * value));
- }
- });
- return mAnimator;
- }
-
- /**
- * Creates a bitmap with the given width and height.
- *
- * If it fails with an OutOfMemory error, it will force a GC and then try to create the bitmap
- * one more time.
- *
- * @param width width of the bitmap
- * @param height height of the bitmap
- */
- protected static Bitmap createBitmapAndGcIfNecessary(int width, int height) {
- try {
- return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- } catch (OutOfMemoryError e) {
- System.gc();
- return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- }
- }
-}
\ No newline at end of file
diff --git a/shimmer/src/main/res/layout/viewholder_shimmer.xml b/shimmer/src/main/res/layout/viewholder_shimmer.xml
index 0f62fe2..f56a531 100644
--- a/shimmer/src/main/res/layout/viewholder_shimmer.xml
+++ b/shimmer/src/main/res/layout/viewholder_shimmer.xml
@@ -15,14 +15,9 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/shimmer/src/main/res/values/attrs.xml b/shimmer/src/main/res/values/attrs.xml
index 7711a74..7acdeeb 100644
--- a/shimmer/src/main/res/values/attrs.xml
+++ b/shimmer/src/main/res/values/attrs.xml
@@ -26,5 +26,8 @@ limitations under the License.
+
+
+
\ No newline at end of file
diff --git a/shimmer/src/main/res/values/colors.xml b/shimmer/src/main/res/values/colors.xml
new file mode 100644
index 0000000..801d7df
--- /dev/null
+++ b/shimmer/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #16000000
+ #24000000
+ #e3e1e3
+
\ No newline at end of file
diff --git a/shimmer/src/main/res/values/shimmer_attrs.xml b/shimmer/src/main/res/values/shimmer_attrs.xml
deleted file mode 100644
index 1aa021f..0000000
--- a/shimmer/src/main/res/values/shimmer_attrs.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/shimmer/src/main/res/values/strings.xml b/shimmer/src/main/res/values/strings.xml
new file mode 100644
index 0000000..49a98bf
--- /dev/null
+++ b/shimmer/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ shimmer
+
\ No newline at end of file
diff --git a/shimmer/src/main/res/values/values.xml b/shimmer/src/main/res/values/values.xml
deleted file mode 100644
index 2d84c24..0000000
--- a/shimmer/src/main/res/values/values.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
- shimmer
- #16000000
- #24000000
-
-