aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGriffin Millender <griffinn.millender@gmail.com>2016-10-12 23:33:23 -0500
committerGriffin Millender <griffinn.millender@gmail.com>2016-10-13 22:03:44 -0500
commit0127e9ab2e14c29de7234bb736c0aee33cf9caf3 (patch)
treef6d77d3cd9c1eb58d7f9cd349e0516bd3fb7fb5d
parent857c1b59f2015177bd1b34155c4434e8bd498790 (diff)
Add CardRecyclerView
Change-Id: Id77fad4845c259cfd3eeab5acb14b6b28fd0e773
-rw-r--r--Android.mk3
-rw-r--r--res/layout/native_recyclerview_card_layout.xml34
-rw-r--r--res/layout/native_recyclerview_card_thumbnail_layout.xml31
-rw-r--r--res/values/styles.xml15
-rw-r--r--src/com/android/cards/recyclerview/internal/BaseRecyclerViewAdapter.java211
-rw-r--r--src/com/android/cards/recyclerview/internal/CardArrayRecyclerViewAdapter.java165
-rw-r--r--src/com/android/cards/recyclerview/internal/ViewAdapterImpl.java42
-rw-r--r--src/com/android/cards/recyclerview/view/CardRecyclerView.java325
8 files changed, 826 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
index 330237f..4df58fa 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,6 +19,9 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v4 \
android-support-v7-cardview
+LOCAL_JAVA_LIBRARIES := \
+ android-support-v7-recyclerview
+
LOCAL_MODULE := android-opt-cards
LOCAL_SDK_VERSION := 21
diff --git a/res/layout/native_recyclerview_card_layout.xml b/res/layout/native_recyclerview_card_layout.xml
new file mode 100644
index 0000000..c5ecb9c
--- /dev/null
+++ b/res/layout/native_recyclerview_card_layout.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<!-- You can customize this layout.
+ You need to have in your layout a `CardView` with the ID `list_cardId` -->
+
+
+ <it.gmariotti.cardslib.library.view.CardViewNative
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/list_cardId"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/native_recyclerview_card.base"
+ card:card_layout_resourceID="@layout/native_card_layout"/>
+
+
diff --git a/res/layout/native_recyclerview_card_thumbnail_layout.xml b/res/layout/native_recyclerview_card_thumbnail_layout.xml
new file mode 100644
index 0000000..12c99cc
--- /dev/null
+++ b/res/layout/native_recyclerview_card_thumbnail_layout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ *******************************************************************************
+ ~ Copyright (c) 2013-2014 Gabriele Mariotti.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ *****************************************************************************
+ -->
+
+<!-- You can customize this layout.
+ You need to have in your layout a `CardView` with the ID `list_cardId` -->
+<it.gmariotti.cardslib.library.view.CardViewNative
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/list_cardId"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/native_recyclerview_card.thumbnail"
+ card:card_layout_resourceID="@layout/native_card_thumbnail_layout"
+ />
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 638a8ec..2390f26 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -454,6 +454,21 @@
<item name="android:layout_marginBottom">@dimen/card_section_title_margin_top</item>
</style>
+ <!--Recycler view-->
+ <style name="native_recyclerview_card">
+ <item name="android:layout_marginStart">@dimen/native_recyclerview_card_margin_start</item>
+ <item name="android:layout_marginEnd">@dimen/native_recyclerview_card_margin_end</item>
+ <item name="android:layout_marginBottom">@dimen/native_recyclerview_card_margin_bottom</item>
+ <item name="android:layout_marginTop">@dimen/native_recyclerview_card_margin_top</item>
+ </style>
+
+ <style name="native_recyclerview_card.base" >
+
+ </style>
+ <!-- Thumbnail list -->
+ <style name="native_recyclerview_card.thumbnail">
+
+ </style>
</resources>
diff --git a/src/com/android/cards/recyclerview/internal/BaseRecyclerViewAdapter.java b/src/com/android/cards/recyclerview/internal/BaseRecyclerViewAdapter.java
new file mode 100644
index 0000000..a6e6b00
--- /dev/null
+++ b/src/com/android/cards/recyclerview/internal/BaseRecyclerViewAdapter.java
@@ -0,0 +1,211 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.recyclerview.internal;
+
+import android.content.Context;
+import android.support.annotation.LayoutRes;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.cards.R;
+import com.android.cards.internal.Card;
+import com.android.cards.recyclerview.view.CardRecyclerView;
+import com.android.cards.view.base.CardViewWrapper;
+
+/**
+ * Base RecyclerViewAdapter for RecyclerView and its implemetations.
+ *
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public abstract class BaseRecyclerViewAdapter extends RecyclerView.Adapter<BaseRecyclerViewAdapter.CardViewHolder> implements ViewAdapterImpl {
+
+ /**
+ * Current context
+ */
+ protected Context mContext;
+
+ /**
+ * Default layout used for each row
+ */
+ protected @LayoutRes int mRowLayoutId = R.layout.list_card_layout;
+
+ /**
+ * Used to set the viewTypeCount
+ */
+ protected int typeCardCount = 1;
+
+ /**
+ * Array of layout resource ids
+ */
+ protected @LayoutRes int[] mRowLayoutIds;
+
+ /**
+ * {@link CardRecyclerView}
+ */
+ protected CardRecyclerView mCardRecyclerView;
+
+ // -------------------------------------------------------------
+ // Constructors
+ // -------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param context The current context.
+ */
+ public BaseRecyclerViewAdapter(Context context) {
+ super();
+ mContext = context;
+ }
+
+ // -------------------------------------------------------------
+ // ViewHolder
+ // -------------------------------------------------------------
+
+ public static class CardViewHolder extends RecyclerView.ViewHolder {
+
+ public final CardViewWrapper mCardView;
+ public boolean recycled = false;
+
+ public CardViewHolder(View view) {
+ super(view);
+ mCardView = (CardViewWrapper) view.findViewById(R.id.list_cardId);
+ }
+ }
+
+ @Override
+ public CardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+
+ if (mRowLayoutIds == null || mRowLayoutIds.length == 0) {
+ final View view = LayoutInflater.from(mContext).inflate(mRowLayoutId, parent, false);
+ return new CardViewHolder(view);
+ } else {
+ final View view = LayoutInflater.from(mContext).inflate(mRowLayoutIds[viewType], parent, false);
+ return new CardViewHolder(view);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(CardViewHolder cardViewHolder, int position) {
+
+ CardViewWrapper mCardView = cardViewHolder.mCardView;
+ Card mCard = getItem(position);
+
+ //Setup card
+ if (mCardView != null) {
+ //It is important to set recycle value for inner layout elements
+ mCardView.setForceReplaceInnerLayout(Card.equalsInnerLayout(mCardView.getCard(),mCard));
+
+ //It is important to set recycle value for performance issue
+ mCardView.setRecycle(cardViewHolder.recycled);
+
+ //Save original swipeable to prevent cardSwipeListener (listView requires another cardSwipeListener)
+ boolean origianlSwipeable = mCard.isSwipeable();
+ mCard.setSwipeable(false);
+
+ mCardView.setCard(mCard);
+
+ //Set originalValue
+ mCard.setSwipeable(origianlSwipeable);
+
+ //If card has an expandable button override animation
+ if ((mCard.getCardHeader() != null && mCard.getCardHeader().isButtonExpandVisible()) || mCard.getViewToClickToExpand()!=null ){
+ setupExpandCollapseListAnimation(mCardView);
+ }
+
+ //Setup swipeable animation
+ //setupSwipeableAnimation(mCard, mCardView);
+ }
+ }
+
+ /**
+ * Overrides the default collapse/expand animation in a List
+ *
+ * @param cardView {@link com.android.cards.view.base.CardViewWrapper}
+ */
+ protected void setupExpandCollapseListAnimation(CardViewWrapper cardView) {
+
+ if (cardView == null) return;
+ cardView.setOnExpandListAnimatorListener(mCardRecyclerView);
+ }
+
+ // -------------------------------------------------------------
+ // Views
+ // -------------------------------------------------------------
+
+ public int getTypeCardCount() {
+ return typeCardCount;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ Card card = (Card) getItem(position);
+ return card.getType();
+ }
+
+ /**
+ * Override this method to obtain a Card from a position
+ *
+ * @param position
+ * @return
+ */
+ public abstract Card getItem(int position);
+
+ /**
+ * Sets layout resource ID used by rows
+ *
+ * @param rowLayoutId layout resource id
+ */
+ public void setRowLayoutId(@LayoutRes int rowLayoutId) {
+ this.mRowLayoutId = rowLayoutId;
+ }
+
+ /**
+ * Sets layouts resource ID used by rows
+ *
+ * @param rowLayoutIds array of layout resource ids
+ */
+ public void setRowLayoutIds(@LayoutRes int[] rowLayoutIds) {
+ mRowLayoutIds = rowLayoutIds;
+ if (rowLayoutIds != null)
+ typeCardCount = rowLayoutIds.length;
+ else
+ typeCardCount = 1;
+ }
+
+ /**
+ *
+ * @return the RecyclerView
+ */
+ public CardRecyclerView getCardRecyclerView() {
+ return mCardRecyclerView;
+ }
+
+ /**
+ * Sets the RecyclerView
+ *
+ * @param cardRecyclerView
+ */
+ public void setCardRecyclerView(CardRecyclerView cardRecyclerView) {
+ mCardRecyclerView = cardRecyclerView;
+ }
+
+}
diff --git a/src/com/android/cards/recyclerview/internal/CardArrayRecyclerViewAdapter.java b/src/com/android/cards/recyclerview/internal/CardArrayRecyclerViewAdapter.java
new file mode 100644
index 0000000..77c755f
--- /dev/null
+++ b/src/com/android/cards/recyclerview/internal/CardArrayRecyclerViewAdapter.java
@@ -0,0 +1,165 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.recyclerview.internal;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.android.cards.internal.Card;
+
+/**
+ * RecyclerView with an ArrayAdapter.
+ *
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class CardArrayRecyclerViewAdapter extends BaseRecyclerViewAdapter {
+
+ /**
+ * Internal objects
+ */
+ protected List<Card> mCards;
+
+ // -------------------------------------------------------------
+ // Constructors
+ // -------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param context The current context.
+ * @param cards The cards to represent in the ListView.
+ */
+ public CardArrayRecyclerViewAdapter(Context context, List<Card> cards) {
+ super(context);
+ if (cards != null) {
+ mCards = cards;
+ } else {
+ mCards = new ArrayList<Card>();
+ }
+ }
+
+ // -------------------------------------------------------------
+ // Methods
+ // -------------------------------------------------------------
+
+ @Override
+ public int getItemCount() {
+ return mCards.size();
+ }
+
+
+ @Override
+ public Card getItem(int position) {
+ return mCards.get(position);
+ }
+
+ /**
+ * Sets the card's list
+ * @param cards list
+ */
+ public void setCards(List<Card> cards) {
+ mCards = cards;
+ }
+
+ /**
+ * Appends the specified element to the end of the {@code List}.
+ *
+ * @param card the object to add.
+ *
+ * @return always true.
+ */
+ @Override
+ public boolean add(@NonNull final Card card) {
+ boolean result = mCards.add(card);
+ notifyDataSetChanged();
+ return result;
+ }
+
+ /**
+ * Appends the specified element into the index specified {@code List}.
+ * @param index
+ * @param card
+ */
+ @Override
+ public void add(final int index, @NonNull final Card card) {
+ mCards.add(index, card);
+ notifyItemInserted(index);
+ }
+
+ /**
+ * Adds the objects in the specified collection to the end of this List. The objects are added in the order in which they are returned from the collection's iterator.
+ *
+ * @param collection the collection of objects.
+ *
+ * @return {@code true} if this {@code List} is modified, {@code false} otherwise.
+ */
+ public boolean addAll(@NonNull final Collection<? extends Card> collection) {
+ boolean result = mCards.addAll(collection);
+ notifyDataSetChanged();
+ return result;
+ }
+
+ /**
+ * Check if the list contains the element
+ * @param card
+ * @return
+ */
+ @Override
+ public boolean contains(final Card card) {
+ return mCards.contains(card);
+ }
+
+ /**
+ * Clears the list
+ */
+ @Override
+ public void clear() {
+ mCards.clear();
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Removes the specified element
+ * @param card
+ * @return
+ */
+ @Override
+ public boolean remove(@NonNull final Card card) {
+ boolean result = mCards.remove(card);
+ notifyDataSetChanged();
+ return result;
+ }
+
+ /**
+ * Removes the element at position
+ * @param position
+ * @return
+ */
+ @NonNull
+ @Override
+ public Card remove(final int position) {
+ Card result = mCards.remove(position);
+ notifyItemRemoved(position);
+ return result;
+ }
+}
diff --git a/src/com/android/cards/recyclerview/internal/ViewAdapterImpl.java b/src/com/android/cards/recyclerview/internal/ViewAdapterImpl.java
new file mode 100644
index 0000000..40c93fa
--- /dev/null
+++ b/src/com/android/cards/recyclerview/internal/ViewAdapterImpl.java
@@ -0,0 +1,42 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.recyclerview.internal;
+
+import android.support.annotation.NonNull;
+
+import com.android.cards.internal.Card;
+
+/**
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public interface ViewAdapterImpl {
+
+ public boolean add(@NonNull final Card card);
+
+ public void add(final int index, @NonNull final Card card) ;
+
+ public boolean remove(@NonNull final Card card);
+
+ public Card remove(final int position);
+
+ public boolean contains(final Card object);
+
+ public void clear();
+
+}
diff --git a/src/com/android/cards/recyclerview/view/CardRecyclerView.java b/src/com/android/cards/recyclerview/view/CardRecyclerView.java
new file mode 100644
index 0000000..f6f94d1
--- /dev/null
+++ b/src/com/android/cards/recyclerview/view/CardRecyclerView.java
@@ -0,0 +1,325 @@
+/*
+ * ******************************************************************************
+ * Copyright (c) 2013-2014 Gabriele Mariotti.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * *****************************************************************************
+ */
+
+package com.android.cards.recyclerview.view;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.annotation.LayoutRes;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.cards.R;
+import com.android.cards.internal.Card;
+import com.android.cards.recyclerview.internal.BaseRecyclerViewAdapter;
+import com.android.cards.view.base.CardViewWrapper;
+
+
+/**
+ *
+ * RecyclerView for Cards.
+ * It uses a {@link BaseRecyclerViewAdapter} to populate items.
+ * </p>
+ * Usage:
+ * <pre><code>
+ * <com.android.cards.recyclerview.view.CardRecyclerView
+ * android:layout_width="match_parent"
+ * android:layout_height="match_parent"
+ * android:id="@+id/listId"
+ * card:list_card_layout_resourceID="@layout/list_card_thumbnail_layout" /> *
+ * </code></pre>
+ * It provides a default layout id for each row @layout/list_card_layout
+ * Use can easily customize it using card:list_card_layout_resourceID attr in your xml layout.
+ * </p>
+ *
+ * @author Gabriele Mariotti (gabri.mariotti@gmail.com)
+ */
+public class CardRecyclerView extends RecyclerView implements CardViewWrapper.OnExpandListAnimatorListener {
+
+ /**
+ * Card Adapter
+ */
+ protected BaseRecyclerViewAdapter mAdapter;
+
+ //--------------------------------------------------------------------------
+ // Custom Attrs
+ //--------------------------------------------------------------------------
+
+ /**
+ * Default layout to apply to card
+ */
+ protected @LayoutRes
+ int list_card_layout_resourceID = R.layout.list_card_layout;
+
+ /**
+ * Layouts to apply to card
+ */
+ protected @LayoutRes int[] list_card_layout_resourceIDs;
+
+ //--------------------------------------------------------------------------
+ // Constructors
+ //--------------------------------------------------------------------------
+
+ public CardRecyclerView(Context context) {
+ super(context);
+ init(context, null, 0);
+ }
+
+ public CardRecyclerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs, 0);
+ }
+
+ public CardRecyclerView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context, attrs, defStyle);
+ }
+
+ //--------------------------------------------------------------------------
+ // Init
+ //--------------------------------------------------------------------------
+
+ /**
+ * Initialize
+ *
+ * @param attrs
+ * @param defStyle
+ */
+ protected void init(Context context,AttributeSet attrs, int defStyle){
+
+ //Init attrs
+ initAttrs(context,attrs,defStyle);
+
+ }
+
+
+ /**
+ * Init custom attrs.
+ *
+ * @param attrs
+ * @param defStyle
+ */
+ protected void initAttrs(Context context,AttributeSet attrs, int defStyle) {
+
+ list_card_layout_resourceID = R.layout.list_card_layout;
+
+ TypedArray a = context.getTheme().obtainStyledAttributes(
+ attrs, R.styleable.card_options, defStyle, defStyle);
+
+ try {
+ list_card_layout_resourceID = a.getResourceId(R.styleable.card_options_list_card_layout_resourceID, this.list_card_layout_resourceID);
+
+ int arrayIds = a.getResourceId(R.styleable.card_options_list_card_layout_resourceIDs, 0);
+ if (arrayIds > 0 ) {
+ TypedArray layouts = context.getResources().obtainTypedArray(arrayIds);
+ if (layouts != null){
+ list_card_layout_resourceIDs = new int[layouts.length()];
+ for (int i=0; i<layouts.length();i++){
+ list_card_layout_resourceIDs[i] = layouts.getResourceId(i, R.layout.list_card_layout);
+ }
+ }
+ layouts.recycle();
+ }
+
+
+ } finally {
+ a.recycle();
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Adapter
+ //--------------------------------------------------------------------------
+
+ /**
+ * Set {@link com.android.cards.recyclerview.internal.BaseRecyclerViewAdapter} and layout used by items in RecyclerView
+ *
+ * @param adapter {@link com.android.cards.recyclerview.internal.BaseRecyclerViewAdapter}
+ */
+ public void setAdapter(BaseRecyclerViewAdapter adapter) {
+ super.setAdapter(adapter);
+
+ //Set Layout used by items
+ adapter.setRowLayoutId(list_card_layout_resourceID);
+ adapter.setRowLayoutIds(list_card_layout_resourceIDs);
+ adapter.setCardRecyclerView(this);
+
+ mAdapter=adapter;
+
+ setRecyclerListener(new RecyclerView.RecyclerListener() {
+ @Override
+ public void onViewRecycled(RecyclerView.ViewHolder viewHolder) {
+ if (viewHolder instanceof BaseRecyclerViewAdapter.CardViewHolder){
+ ((BaseRecyclerViewAdapter.CardViewHolder)viewHolder).recycled = true;
+ }
+ }
+ });
+ }
+
+ //--------------------------------------------------------------------------
+ // Expand and Collapse animator
+ //--------------------------------------------------------------------------
+
+ @Override
+ public void onExpandStart(CardViewWrapper viewCard,View expandingLayout) {
+ ExpandCollapseHelper.animateExpanding(expandingLayout,viewCard,this);
+ }
+
+ @Override
+ public void onCollapseStart(CardViewWrapper viewCard,View expandingLayout) {
+ ExpandCollapseHelper.animateCollapsing(expandingLayout,viewCard,this);
+ }
+
+ /**
+ * Helper to animate collapse and expand animation
+ */
+ private static class ExpandCollapseHelper {
+
+ /**
+ * This method expandes the view that was clicked.
+ *
+ * @param expandingLayout layout to expand
+ * @param cardView cardView
+ * @param recyclerView recyclerView
+ */
+ public static void animateCollapsing(final View expandingLayout, final CardViewWrapper cardView,final RecyclerView recyclerView) {
+ int origHeight = expandingLayout.getHeight();
+
+ ValueAnimator animator = createHeightAnimator(expandingLayout, origHeight, 0);
+ animator.addListener(new AnimatorListenerAdapter() {
+
+ @Override
+ public void onAnimationEnd(final Animator animator) {
+ expandingLayout.setVisibility(View.GONE);
+
+ cardView.setExpanded(false);//card.setExpanded(true);
+
+ notifyAdapter(recyclerView,recyclerView.getLayoutManager().getPosition((View)cardView));
+
+ Card card = cardView.getCard();
+ if (card.getOnCollapseAnimatorEndListener()!=null)
+ card.getOnCollapseAnimatorEndListener().onCollapseEnd(card);
+ }
+ });
+ animator.start();
+ }
+
+ /**
+ * This method collapse the view that was clicked.
+ *
+ * @param expandingLayout layout to collapse
+ * @param cardView cardView
+ * @param recyclerView recyclerView
+ */
+ public static void animateExpanding(final View expandingLayout, final CardViewWrapper cardView,final RecyclerView recyclerView) {
+ /* Update the layout so the extra content becomes visible.*/
+ expandingLayout.setVisibility(View.VISIBLE);
+
+ View parent = (View) expandingLayout.getParent();
+ final int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth() - parent.getPaddingLeft() - parent.getPaddingRight(), View.MeasureSpec.AT_MOST);
+ final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ expandingLayout.measure(widthSpec, heightSpec);
+
+
+ ValueAnimator animator = createHeightAnimator(expandingLayout, 0, expandingLayout.getMeasuredHeight());
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ final int listViewHeight = recyclerView.getHeight();
+ final int listViewBottomPadding = recyclerView.getPaddingBottom();
+
+ final View v = findDirectChild(expandingLayout, recyclerView);
+
+ @Override
+ public void onAnimationUpdate(final ValueAnimator valueAnimator) {
+ if (recyclerView.getLayoutManager().canScrollVertically()) {
+ final int bottom = v.getBottom();
+ if (bottom > listViewHeight) {
+ final int top = v.getTop();
+ if (top > 0) {
+ //recyclerView.scrollBy(0,Math.min(bottom - listViewHeight + listViewBottomPadding, top));
+ recyclerView.smoothScrollBy(0,Math.min(bottom - listViewHeight + listViewBottomPadding + 4, top));
+
+ }
+ }
+ }
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ cardView.setExpanded(true);//card.setExpanded(true);
+
+ notifyAdapter(recyclerView,recyclerView.getLayoutManager().getPosition((View)cardView));
+
+ Card card = cardView.getCard();
+ if (card.getOnExpandAnimatorEndListener()!=null)
+ card.getOnExpandAnimatorEndListener().onExpandEnd(card);
+
+ }
+ });
+ animator.start();
+ }
+
+ private static View findDirectChild(final View view, final RecyclerView recyclerView) {
+ View result = view;
+ View parent = (View) result.getParent();
+ while (parent != recyclerView) {
+ result = parent;
+ parent = (View) result.getParent();
+ }
+ return result;
+ }
+
+ public static ValueAnimator createHeightAnimator(final View view, final int start, final int end) {
+ ValueAnimator animator = ValueAnimator.ofInt(start, end);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(final ValueAnimator valueAnimator) {
+ int value = (Integer) valueAnimator.getAnimatedValue();
+
+ ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
+ layoutParams.height = value;
+ view.setLayoutParams(layoutParams);
+ }
+ });
+ return animator;
+ }
+
+ /**
+ * This method notifies the adapter after setting expand value inside cards
+ *
+ * @param recyclerView
+ */
+ public static void notifyAdapter(RecyclerView recyclerView,int position){
+
+ if (recyclerView instanceof CardRecyclerView){
+
+ CardRecyclerView cardRecyclerView = (CardRecyclerView) recyclerView;
+ if (cardRecyclerView.mAdapter!=null){
+ cardRecyclerView.mAdapter.notifyItemChanged(position);
+ }
+ }
+ }
+ }
+}