Skip to content

Instantly share code, notes, and snippets.

@gabrielemariotti
Created February 20, 2014 08:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gabrielemariotti/9108993 to your computer and use it in GitHub Desktop.
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.
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