Created
February 20, 2014 08:16
-
-
Save gabrielemariotti/9108993 to your computer and use it in GitHub Desktop.
Cardslib: A code snippet to dismiss a Card in a listView with a Swipe Animation clicking a button.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ListBaseFragment extends BaseFragment { | |
CardListView listView; | |
CardArrayAdapter mCardArrayAdapter; | |
int mAnimationTime=1; | |
private int mDismissAnimationRefCount = 0; | |
private List<PendingDismissData> mPendingDismisses = new ArrayList<PendingDismissData>(); | |
private int mDownPosition; | |
@Override | |
public int getTitleResourceId() { | |
return R.string.carddemo_title_list_base; | |
} | |
@Override | |
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |
return inflater.inflate(R.layout.demo_fragment_list_base, container, false); | |
} | |
@Override | |
public void onActivityCreated(Bundle savedInstanceState) { | |
super.onActivityCreated(savedInstanceState); | |
initCards(); | |
} | |
private void initCards() { | |
ArrayList<Card> cards = new ArrayList<Card>(); | |
for (int i=0;i<200;i++){ | |
CardExample card = new CardExample(getActivity(),"My title "+i,"Inner text "+i); | |
cards.add(card); | |
} | |
mCardArrayAdapter = new CardArrayAdapter(getActivity(),cards); | |
listView = (CardListView) getActivity().findViewById(R.id.carddemo_list_base1); | |
if (listView!=null){ | |
listView.setAdapter(mCardArrayAdapter); | |
} | |
} | |
public class CardExample extends Card{ | |
protected String mTitleHeader; | |
protected String mTitleMain; | |
public CardExample(Context context,String titleHeader,String titleMain) { | |
super(context, R.layout.carddemo_example_inner_content); | |
this.mTitleHeader=titleHeader; | |
this.mTitleMain=titleMain; | |
init(); | |
} | |
private void init(){ | |
//Create a CardHeader | |
CardHeader header = new CardHeader(getActivity()); | |
//Set the header title | |
header.setTitle(mTitleHeader); | |
//Add a popup menu. This method set OverFlow button to visible | |
header.setPopupMenu(R.menu.popupmain, new CardHeader.OnClickCardHeaderPopupMenuListener() { | |
@Override | |
public void onMenuItemClick(BaseCard card, MenuItem item) { | |
dismissiCardWithSwipeAnimation((Card)card,card.getCardView(),true); | |
} | |
}); | |
addCardHeader(header); | |
//Add ClickListener | |
setOnClickListener(new OnCardClickListener() { | |
@Override | |
public void onClick(Card card, View view) { | |
Toast.makeText(getContext(), "Click Listener card=" + mTitleHeader, Toast.LENGTH_SHORT).show(); | |
} | |
}); | |
//Set the card inner text | |
setTitle(mTitleMain); | |
} | |
} | |
//--------------------------------------------------------------------------------------------- | |
// Animation for dismiss a Card with a Swipe Animation | |
// Call this method to start animation | |
//--------------------------------------------------------------------------------------------- | |
private void dismissiCardWithSwipeAnimation(final Card card, final CardView view,boolean dismissRight) { | |
++mDismissAnimationRefCount; | |
mAnimationTime = getActivity().getResources().getInteger( | |
android.R.integer.config_shortAnimTime); | |
int mViewWidth = listView.getWidth(); | |
mDownPosition = listView.getPositionForView(view); | |
view.animate() | |
.translationX(dismissRight ? mViewWidth : -mViewWidth) | |
.alpha(0) | |
.setDuration(mAnimationTime) | |
.setListener(new AnimatorListenerAdapter() { | |
@Override | |
public void onAnimationEnd(Animator animation) { | |
performDismiss(view, mCardArrayAdapter.getPosition(card)); | |
} | |
}); | |
} | |
private void performDismiss(final View dismissView, final int dismissPosition) { | |
// Animate the dismissed list item to zero-height and fire the dismiss callback when | |
// all dismissed list item animations have completed. This triggers layout on each animation | |
// frame; in the future we may want to do something smarter and more performant. | |
final ViewGroup.LayoutParams lp = dismissView.getLayoutParams(); | |
final int originalHeight = dismissView.getHeight(); | |
ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime); | |
animator.addListener(new AnimatorListenerAdapter() { | |
@Override | |
public void onAnimationEnd(Animator animation) { | |
--mDismissAnimationRefCount; | |
if (mDismissAnimationRefCount == 0) { | |
// No active animations, process all pending dismisses. | |
// Sort by descending position | |
Collections.sort(mPendingDismisses); | |
int[] dismissPositions = new int[mPendingDismisses.size()]; | |
for (int i = mPendingDismisses.size() - 1; i >= 0; i--) { | |
dismissPositions[i] = mPendingDismisses.get(i).position; | |
} | |
mCallbacks.onDismiss(listView, dismissPositions); | |
// Reset mDownPosition to avoid MotionEvent.ACTION_UP trying to start a dismiss | |
// animation with a stale position | |
mDownPosition = ListView.INVALID_POSITION; | |
ViewGroup.LayoutParams lp; | |
for (PendingDismissData pendingDismiss : mPendingDismisses) { | |
// Reset view presentation | |
pendingDismiss.view.setAlpha(1f); | |
pendingDismiss.view.setTranslationX(0); | |
lp = pendingDismiss.view.getLayoutParams(); | |
lp.height = 0; | |
pendingDismiss.view.setLayoutParams(lp); | |
} | |
// Send a cancel event | |
long time = SystemClock.uptimeMillis(); | |
MotionEvent cancelEvent = MotionEvent.obtain(time, time, | |
MotionEvent.ACTION_CANCEL, 0, 0, 0); | |
listView.dispatchTouchEvent(cancelEvent); | |
mPendingDismisses.clear(); | |
} | |
} | |
}); | |
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | |
@Override | |
public void onAnimationUpdate(ValueAnimator valueAnimator) { | |
lp.height = (Integer) valueAnimator.getAnimatedValue(); | |
dismissView.setLayoutParams(lp); | |
} | |
}); | |
mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView)); | |
animator.start(); | |
} | |
class PendingDismissData implements Comparable<PendingDismissData> { | |
public int position; | |
public View view; | |
public PendingDismissData(int position, View view) { | |
this.position = position; | |
this.view = view; | |
} | |
@Override | |
public int compareTo(PendingDismissData other) { | |
// Sort by descending position | |
return other.position - position; | |
} | |
} | |
SwipeDismissListViewTouchListener.DismissCallbacks mCallbacks = new SwipeDismissListViewTouchListener.DismissCallbacks() { | |
@Override | |
public boolean canDismiss(int position, Card card) { | |
return card.isSwipeable(); | |
} | |
@Override | |
public void onDismiss(ListView listView, int[] reverseSortedPositions) { | |
int[] itemPositions=new int[reverseSortedPositions.length]; | |
String[] itemIds=new String[reverseSortedPositions.length]; | |
int i=0; | |
//Remove cards and notifyDataSetChanged | |
for (int position : reverseSortedPositions) { | |
Card card = mCardArrayAdapter.getItem(position); | |
itemPositions[i]=position; | |
itemIds[i]=card.getId(); | |
i++; | |
if (card.isExpanded()){ | |
if (card.getCardView()!=null && card.getCardView().getOnExpandListAnimatorListener()!=null){ | |
//There is a List Animator. | |
card.getCardView().getOnExpandListAnimatorListener().onCollapseStart(card.getCardView(), card.getCardView().getInternalExpandLayout()); | |
} | |
} | |
mCardArrayAdapter.remove(card); | |
if (card.getOnSwipeListener() != null){ | |
card.getOnSwipeListener().onSwipe(card); | |
} | |
} | |
mCardArrayAdapter.notifyDataSetChanged(); | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment