Android Open Source - AndroidSwipeListActions List View Swipe Gesture






From Project

Back to project page AndroidSwipeListActions.

License

The source code is released under:

Apache License

If you think the Android project AndroidSwipeListActions listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.rbware.swipelistactions;
// w w w  .j a  va  2  s.  c o m
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ActionBar.LayoutParams;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.Log;
import android.view.*;
import android.view.View.OnTouchListener;
import android.widget.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


@SuppressWarnings("ConstantConditions")
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
public class ListViewSwipeGesture implements View.OnTouchListener {
    Activity activity;
    
    

    // Cached ViewConfiguration and system-wide constant values
    private int mSlop;
    private int mMinFlingVelocity;
    private int mMaxFlingVelocity;
    private long mAnimationTime;

    // Fixed properties
    private ListView mListView;



    //private DismissCallbacks mCallbacks;
    private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
    private int smallWidth = 1;
    private int largewidth = 1;
    private int textwidth = 1;
    private int textwidth2 = 1;
    private int textheight = 1;

    // Transient properties
    private List<PendingDismissData> mPendingDismisses = new ArrayList<PendingDismissData>();
    private int mDismissAnimationRefCount = 0;
    private float mDownX;
    private boolean mSwiping;
    private VelocityTracker mVelocityTracker;
    private int mDownPosition;
    private int temp_position,opened_position,stagged_position;
    private ViewGroup mDownView,old_mDownView;
    private ViewGroup mDownView_parent;
    private TextView mDownView_parent_txt1,mDownView_parent_txt2;
    private boolean mPaused;
    public boolean moptionsDisplay=false;
    static TouchCallbacks tcallbacks;

    //Intermediate Usages
    String TextColor="#FFFFFF";      //#FF4444
    String RangeOneColor="#FFD060";   //"#FFD060"
    String RangeTwoColor="#92C500";
    String singleColor="#FF4444";

    //Functional  Usages
    public String HalfColor;          //Green
    public String FullColor;         //Orange
    public String HalfText;
    public String FullText;
    public String HalfTextFinal;
    public String FullTextFinal;
    public Drawable HalfDrawable;
    public Drawable FullDrawable;


    //Swipe Types
    public int SwipeType;
    public static int Single  =  1;
    public static int Double  =  2;
    public static int Dismiss  =  3;

    public ListViewSwipeGesture(ListView listView,TouchCallbacks Callbacks,Activity context){
        ViewConfiguration vc    =   ViewConfiguration.get(listView.getContext());
        mSlop                   =   vc.getScaledTouchSlop();
        mMinFlingVelocity       =   vc.getScaledMinimumFlingVelocity() * 16;
        mMaxFlingVelocity       =   vc.getScaledMaximumFlingVelocity();
        mListView               =   listView;
        activity                =   context;
        tcallbacks              =   Callbacks;
        SwipeType               =   Double;
        GetResourcesValues();

        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                                    long arg3) {            //Invokes OnClick Functionality
                if(!moptionsDisplay){
                    tcallbacks.OnClickListView(temp_position);
                }

            }
        });
    }



    public interface TouchCallbacks {                                           //Callback functions
        void FullSwipeListView(int position);
        void HalfSwipeListView(int position);
        void OnClickListView(int position);
        void LoadDataForScroll(int count);
        void onDismiss(ListView listView, int[] reverseSortedPositions);
    }

    private void GetResourcesValues() {
        mAnimationTime          =   mListView.getContext().getResources().getInteger(
                android.R.integer.config_shortAnimTime);
        HalfColor           =   RangeOneColor;          //Green
        FullColor           =   activity.getResources().getString(R.string.str_orange);         //Orange
        HalfText            =   activity.getResources().getString(R.string.basic_action_1);
        HalfTextFinal         =   activity.getResources().getString(R.string.basic_action_1);
        FullText            =   activity.getResources().getString(R.string.basic_action_2);
        FullTextFinal         =   activity.getResources().getString(R.string.basic_action_2);
        HalfDrawable        =   activity.getResources().getDrawable( R.drawable.rating_good );
        FullDrawable        =   activity.getResources().getDrawable(R.drawable.rating_favorite);
    }


    public void setEnabled(boolean enabled) {
        mPaused     =   !enabled;
    }

    public GestureScroll makeScrollListener() {
        return new GestureScroll();
    }



    class  GestureScroll implements AbsListView.OnScrollListener{
        //Scroll Usages
        private int visibleThreshold    =   4;
        private int currentPage         =   0;
        private int previousTotal       =   0;
        private boolean loading         =   true;
        private int previousFirstVisibleItem = 0;
        private long previousEventTime = 0, currTime, timeToScrollOneElement;
        private double speed = 0;

        @Override
        public void onScrollStateChanged(AbsListView absListView, int scrollState) {
            setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                             int visibleItemCount, int totalItemCount) {
            if (loading) {
                if (totalItemCount > previousTotal) {
                    loading = false;
                    previousTotal   =   totalItemCount;
                    currentPage++;
                }
            }

            if ( !loading  && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
                tcallbacks.LoadDataForScroll(totalItemCount);
                loading = true;
            }

            if (previousFirstVisibleItem != firstVisibleItem) {
                currTime = System.currentTimeMillis();
                timeToScrollOneElement = currTime - previousEventTime;
                speed = ((double) 1 / timeToScrollOneElement) * 1000;

                previousFirstVisibleItem = firstVisibleItem;
                previousEventTime = currTime;

            }

        }

        public double getSpeed() {
            return speed;
        }
    }



    @SuppressLint("ResourceAsColor")
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
    @Override
    public boolean onTouch(final View view, MotionEvent event) {
        if (mViewWidth < 2) {
            mViewWidth  =   mListView.getWidth();
            smallWidth  =  mViewWidth/7;
            textwidth2  =  mViewWidth/3;
            textwidth  =  textwidth2;
            largewidth  =  textwidth+textwidth2;
        }

        int tempwidth  =  0;
        if(SwipeType==1)
            tempwidth = smallWidth;
        else
            tempwidth = textwidth2;

         switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN: {
                if (mPaused) {
                    return false;
                }
                Rect rect               =   new Rect();
                int childCount          =   mListView.getChildCount();
                int[] listViewCoords    = new int[2];
                mListView.getLocationOnScreen(listViewCoords);
                int x                   = (int) event.getRawX() - listViewCoords[0];
                int y                   = (int) event.getRawY() - listViewCoords[1];
                ViewGroup child;
                for (int i = 0; i < childCount; i++) {
                    child = (ViewGroup) mListView.getChildAt(i);
                    child.getHitRect(rect);
                    if (rect.contains(x, y)) {
                        mDownView_parent    =   child;
                        mDownView           =   (ViewGroup) child.findViewById(R.id.list_display_view_container);
                        if(mDownView_parent.getChildCount()==1){
                            textheight  =  mDownView_parent.getHeight();
                            if(SwipeType==Dismiss){
                                HalfColor    =  singleColor;
                                HalfDrawable  =  activity.getResources().getDrawable(R.drawable.content_discard);
                            }
                           SetBackGroundforList();
                        }


                        if(old_mDownView!=null && mDownView!=old_mDownView){
                            ResetListItem(old_mDownView);
                            old_mDownView=null;
                            return false;
                        }
                        break;
                    }
                }

                if (mDownView != null) {
                    mDownX              =   event.getRawX();
                    mDownPosition       =   mListView.getPositionForView(mDownView);
                    mVelocityTracker    =   VelocityTracker.obtain();
                    mVelocityTracker.addMovement(event);
                } else {
                    mDownView               =   null;
                }

                //mSwipeDetected              =   false;
                temp_position               =   mListView.pointToPosition((int) event.getX(), (int) event.getY());
                view.onTouchEvent(event);
                return true;
            }

            case MotionEvent.ACTION_UP: {
                if (mVelocityTracker == null) {
                    break;
                }
                float deltaX                =   event.getRawX() - mDownX;
                mVelocityTracker.addMovement(event);
                mVelocityTracker.computeCurrentVelocity(1000); // 1000 by defaut but
                float velocityX             =   mVelocityTracker.getXVelocity();                      // it was too much
                float absVelocityX          =   Math.abs(velocityX);
                float absVelocityY          =   Math.abs(mVelocityTracker.getYVelocity());
                boolean swipe               =   false;
                boolean swipeRight          =   false;

                if (Math.abs(deltaX) > tempwidth) {
                    swipe               =   true;
                    swipeRight          =   deltaX > 0;

                }else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity && absVelocityY < absVelocityX) {
                    // dismiss only if flinging in the same direction as dragging
                    swipe   = (velocityX < 0) == (deltaX < 0);
                    swipeRight          = mVelocityTracker.getXVelocity() > 0;
                }

                if (deltaX < 0 && swipe) {
                    mListView.setDrawSelectorOnTop(false);

                    if (swipe && !swipeRight && deltaX <= -tempwidth) {
                        FullSwipeTrigger();
                    } else if (deltaX >= -textwidth && SwipeType==Double) {
                        ResetListItem(mDownView);
                    }else {
                        ResetListItem(mDownView);
                    }
                } else {
                    ResetListItem(mDownView);
                }

                mVelocityTracker.recycle();
                mVelocityTracker    =   null;
                mDownX              =   0;
                mDownView           =   null;
                mDownPosition       =   ListView.INVALID_POSITION;
                mSwiping            =   false;
                break;
            }

            case MotionEvent.ACTION_MOVE: {

                float deltaX = event.getRawX() - mDownX;
                if (mVelocityTracker == null || mPaused ||deltaX>0) {
                    break;
                }

                mVelocityTracker.addMovement(event);


                if (Math.abs(deltaX) > mSlop) {
                    mSwiping = true;
                    mListView.requestDisallowInterceptTouchEvent(true);

                    // Cancel ListView's touch (un-highlighting the item)
                    MotionEvent cancelEvent     =   MotionEvent.obtain(event);
                    cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
                            (event.getActionIndex()
                                    << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
                    mListView.onTouchEvent(cancelEvent);
                    cancelEvent.recycle();
                }
                if (mSwiping && deltaX < 0 ) {

                    int width;
                    if(SwipeType==1){
                        width  =  textwidth;
                    }
                    else{
                        width  =  largewidth;
                    }

                    if (-deltaX<width){
                        mDownView.setTranslationX(deltaX);
                        return false;
                    }
                    return false;
                }else if(mSwiping){
                    ResetListItem(mDownView);
                }
                break;
            }
        }
        return false;
    }




    private void SetBackGroundforList() {
    // TODO Auto-generated method stub
       mDownView_parent_txt1 =  new TextView(activity.getApplicationContext());
         RelativeLayout.LayoutParams lp1 =new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,android.widget.RelativeLayout.LayoutParams.WRAP_CONTENT);
         lp1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
         mDownView_parent_txt1.setId(111111);
         mDownView_parent_txt1.setLayoutParams(lp1);
         mDownView_parent_txt1.setGravity( Gravity.CENTER_HORIZONTAL);
         mDownView_parent_txt1.setText(HalfText);
         mDownView_parent_txt1.setWidth(textwidth2);
         mDownView_parent_txt1.setPadding(0, textheight/4, 0, 0);
         mDownView_parent_txt1.setHeight(textheight);
         mDownView_parent_txt1.setBackgroundColor(Color.parseColor(HalfColor));
         mDownView_parent_txt1.setTextColor(Color.parseColor(TextColor));
         mDownView_parent_txt1.setCompoundDrawablesWithIntrinsicBounds(null , HalfDrawable, null, null );
         mDownView_parent.addView(mDownView_parent_txt1, 0);

         if(SwipeType==Double){
             mDownView_parent_txt2 = new TextView(activity.getApplicationContext());
             mDownView_parent_txt2.setId(222222);
             RelativeLayout.LayoutParams lp2 =new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,android.widget.RelativeLayout.LayoutParams.WRAP_CONTENT);
             lp2.addRule(RelativeLayout.LEFT_OF,mDownView_parent_txt1.getId());
             mDownView_parent_txt2.setLayoutParams(lp2);
             mDownView_parent_txt2.setGravity(Gravity.CENTER_HORIZONTAL);
             mDownView_parent_txt2.setText(FullText);
             mDownView_parent_txt2.setWidth(textwidth);
             mDownView_parent_txt2.setPadding(0, textheight/4, 0, 0);
             mDownView_parent_txt2.setHeight(textheight);
             mDownView_parent_txt2.setBackgroundColor(Color.parseColor(FullColor));
             mDownView_parent_txt2.setTextColor(Color.parseColor(TextColor));
             mDownView_parent_txt2.setCompoundDrawablesWithIntrinsicBounds(null , FullDrawable, null, null );
             mDownView_parent.addView(mDownView_parent_txt2, 1);
         }
  }


    private void ResetListItem(View tempView){
        Log.d("Shortlist reset call","Works");

        if(mDismissAnimationRefCount>0)
            mDismissAnimationRefCount=0;

        tempView.animate().translationX(0).alpha(1f).setListener(new AnimatorListenerAdapter(){
            @Override
            public void onAnimationEnd(
                    Animator animation) {
                super.onAnimationEnd(animation);
                int count=mDownView_parent.getChildCount()-1;
                for(int i=0;i<count;i++){
                    View V= mDownView_parent.getChildAt(i);
                    Log.d("removing child class",""+V.getClass());
                    mDownView_parent.removeViewAt(0);
                }
                moptionsDisplay = false;

            }
        });
        stagged_position=-1;
        opened_position=-1;

    }

    private void FullSwipeTrigger(){
        Log.d("FUll Swipe trigger call","Works**********************"+mDismissAnimationRefCount);
        old_mDownView  =  mDownView;
        int width;
        if(SwipeType==Single || SwipeType==Dismiss){
            width  =  textwidth;
            if(SwipeType==Dismiss)
              ++mDismissAnimationRefCount;
        }
        else{
            width  =  largewidth;
        }
        mDownView.animate().translationX(-width).setDuration(300)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(
                            Animator animation) {
                        super.onAnimationEnd(animation);
                        moptionsDisplay     =   true;
                        stagged_position  =  temp_position;
                        mDownView_parent_txt1.setOnTouchListener(new touchClass());
                        if(SwipeType==Double)
                            mDownView_parent_txt2.setOnTouchListener(new touchClass());


                    }

                    @Override
                    public void onAnimationStart(Animator animation) {
                        super.onAnimationStart(animation);
                    }
                });
    }



    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;
        }
    }

    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();

        ((ViewGroup)dismissView).getChildAt(1).animate().translationX(0).alpha(1f).setListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                ((ViewGroup)dismissView).removeViewAt(0);
                Log.d("Selected view", dismissView.getClass()+"..."+dismissView.getId()+mDismissAnimationRefCount);
                ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 0).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;
                                Log.d("Dismiss positions....",dismissPositions[i]+"");
                            }
                            tcallbacks.onDismiss(mListView, dismissPositions);
//                            ViewGroup.LayoutParams lp;
//                          for (PendingDismissData pendingDismiss : mPendingDismisses) {
//                              // Reset view presentation
//                              lp = pendingDismiss.view.getLayoutParams();
//                              lp.height = originalHeight;
//                              pendingDismiss.view.setLayoutParams(lp);
//                          }
                            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 touchClass implements OnTouchListener{

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            opened_position     =   mListView.getPositionForView((View) v.getParent());
            switch (event.getActionMasked()) {
                case MotionEvent.ACTION_DOWN: {
                        if(opened_position==stagged_position && moptionsDisplay){
                            switch (v.getId()) {
                                case 111111:
                                    if(SwipeType==Dismiss){
                                        moptionsDisplay = false;
                                        performDismiss(mDownView_parent,temp_position);
                                    }else
                                        tcallbacks.HalfSwipeListView(temp_position);
                                    return true;
                                case 222222:
                                    tcallbacks.FullSwipeListView(temp_position);
                                    return true;
                            }
                        }
                }
                return false;
            }

            return false;
        }

    }


}




Java Source Code List

com.rbware.swipelistactions.ApplicationTest.java
com.rbware.swipelistactions.ListAdapter.java
com.rbware.swipelistactions.ListViewSwipeGesture.java
com.rbware.swipelistactions.SwipeActivity.java
com.rbware.swipelistactions.TestActivity.java