com.sj.android.appusage.ui.widgets.listview.SwipeListViewTouchListener.java Source code

Java tutorial

Introduction

Here is the source code for com.sj.android.appusage.ui.widgets.listview.SwipeListViewTouchListener.java

Source

/*
 * Copyright (C) 2013 47 Degrees, LLC
 * http://47deg.com
 * hello@47deg.com
 *
 * Copyright 2012 Roman Nurik
 *
 * 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.sj.android.appusage.ui.widgets.listview;

import android.animation.Animator.AnimatorListener;
import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.ListView;

/**
 * Touch listener impl for the SwipeListView
 */
public class SwipeListViewTouchListener implements View.OnTouchListener {

    private int swipeFrontView = 0;
    private int swipeBackView = 0;

    private Rect rect = new Rect();

    // Cached ViewConfiguration and system-wide constant values
    private int slop;
    private int minFlingVelocity;
    private int maxFlingVelocity;

    // Fixed properties
    private SwipeListView swipeListView;
    private int viewWidth = 1; // 1 and not 0 to prevent dividing by zero

    private float downX;
    private float downY;
    private boolean swiping;
    private boolean swipingRight;
    private VelocityTracker velocityTracker;
    private int downPosition;
    private View frontView;
    private View backView;
    private boolean paused;

    private int swipeCurrentAction = SwipeListView.SWIPE_ACTION_REVEAL;

    private int swipeActionLeft = SwipeListView.SWIPE_ACTION_REVEAL;
    private int swipeActionRight = SwipeListView.SWIPE_ACTION_REVEAL;

    public OnItemSwiped mSwipeListener = null;

    public void setOnItemSwiped(OnItemSwiped swipeListener) {
        mSwipeListener = swipeListener;
    }

    public interface OnItemSwiped {
        public void onItemSwiped(int position);
    }

    /**
     * Constructor
     *
     * @param swipeListView  SwipeListView
     * @param swipeFrontView front view Identifier
     * @param swipeBackView  back view Identifier
     */
    public SwipeListViewTouchListener(SwipeListView swipeListView, int swipeFrontView, int swipeBackView) {
        this.swipeFrontView = swipeFrontView;
        this.swipeBackView = swipeBackView;
        ViewConfiguration vc = ViewConfiguration.get(swipeListView.getContext());
        slop = vc.getScaledTouchSlop();
        minFlingVelocity = vc.getScaledMinimumFlingVelocity();
        maxFlingVelocity = vc.getScaledMaximumFlingVelocity();
        this.swipeListView = swipeListView;
    }

    /**
     * Sets current item's front view
     *
     * @param frontView Front view
     */
    private void setFrontView(View frontView, final int childPosition) {
        this.frontView = frontView;

    }

    /**
     * Set current item's back view
     *
     * @param backView
     */
    private void setBackView(View backView) {
        this.backView = backView;
    }

    /**
     * Create animation
     *
     * @param view      affected view
     * @param swap      If state should change. If "false" returns to the original position
     * @param swapRight If swap is true, this parameter tells if move is to the right or left
     * @param position  Position of list
     */
    private void generateAnimate(final View view, final boolean swap, final boolean swapRight, final int position,
            final float deltaX) {
        if (SwipeListView.DEBUG) {
            Log.d(SwipeListView.TAG, "swap: " + swap + " - swapRight: " + swapRight + " - position: " + position);
        }
        if (swipeCurrentAction == SwipeListView.SWIPE_ACTION_REVEAL && swap && swapRight) {
            generateRevealAnimate(view, swap, swapRight, position, deltaX);
        }
    }

    /**
     * Create reveal animation
     *
     * @param view      affected view
     * @param swap      If will change state. If "false" returns to the original position
     * @param swapRight If swap is true, this parameter tells if movement is toward right or left
     * @param position  list position
     */
    private void generateRevealAnimate(final View view, final boolean swap, final boolean swapRight,
            final int position, final float deltaX) {

        view.animate().translationX(viewWidth).setDuration(400).setListener(new AnimatorListener() {

            @Override
            public void onAnimationCancel(android.animation.Animator animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationStart(android.animation.Animator animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(android.animation.Animator animation) {
                if (mSwipeListener != null) {
                    mSwipeListener.onItemSwiped(downPosition);
                }

                resetCell();
            }

            @Override
            public void onAnimationRepeat(android.animation.Animator animation) {
                // TODO Auto-generated method stub

            }
        });
    }

    private void resetCell() {
        if (downPosition != ListView.INVALID_POSITION) {
            if (swipeCurrentAction == SwipeListView.SWIPE_ACTION_REVEAL) {
                backView.setVisibility(View.VISIBLE);
            }
            frontView.setTranslationX(0);
            frontView.setClickable(true);
            frontView.setLongClickable(true);
            frontView = null;
            backView = null;
            downPosition = ListView.INVALID_POSITION;
        }
    }

    /**
     * Set enabled
     *
     * @param enabled
     */
    public void setEnabled(boolean enabled) {
        paused = !enabled;
    }

    View currentChild = null;

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {

        if (viewWidth < 2) {
            viewWidth = swipeListView.getWidth();
        }

        switch (MotionEventCompat.getActionMasked(motionEvent)) {
        case MotionEvent.ACTION_DOWN: {
            if (paused && downPosition != ListView.INVALID_POSITION) {
                return false;
            }
            swipeCurrentAction = SwipeListView.SWIPE_ACTION_REVEAL;

            int childCount = swipeListView.getChildCount();
            int[] listViewCoords = new int[2];
            swipeListView.getLocationOnScreen(listViewCoords);
            int x = (int) motionEvent.getRawX() - listViewCoords[0];
            int y = (int) motionEvent.getRawY() - listViewCoords[1];
            View child;
            for (int i = 0; i < childCount; i++) {
                child = swipeListView.getChildAt(i);
                child.getHitRect(rect);

                int childPosition = swipeListView.getPositionForView(child);

                // dont allow swiping if this is on the header or footer or IGNORE_ITEM_VIEW_TYPE or enabled is false on the adapter
                boolean allowSwipe = swipeListView.getAdapter().isEnabled(childPosition)
                        && swipeListView.getAdapter().getItemViewType(childPosition) >= 0;

                if (allowSwipe && rect.contains(x, y)) {
                    setFrontView(child.findViewById(swipeFrontView), childPosition);
                    currentChild = child;
                    downX = motionEvent.getRawX();
                    downY = motionEvent.getRawY();
                    downPosition = childPosition;

                    frontView.setClickable(false);
                    frontView.setLongClickable(false);

                    velocityTracker = VelocityTracker.obtain();
                    velocityTracker.addMovement(motionEvent);
                    if (swipeBackView > 0) {
                        setBackView(child.findViewById(swipeBackView));
                    }
                    break;
                }
            }
            view.onTouchEvent(motionEvent);
            return true;
        }
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP: {
            if (velocityTracker == null || !swiping || downPosition == ListView.INVALID_POSITION) {
                break;
            }
            float deltaX = motionEvent.getRawX() - downX;
            float deltaY = motionEvent.getRawY() - downY;
            velocityTracker.addMovement(motionEvent);
            velocityTracker.computeCurrentVelocity(1000);
            float velocityX = Math.abs(velocityTracker.getXVelocity());
            float velocityY = Math.abs(velocityTracker.getYVelocity());
            boolean swap = false;
            boolean swapRight = false;
            if (currentChild == null) {
                break;
            }

            if (Math.abs(deltaX) > currentChild.getWidth() / 2
                    && (Math.abs(deltaY) < (currentChild.getHeight() * 3 / 4))) {
                swap = true;
                swapRight = deltaX > 0;
            } else {
                swap = false;
                swapRight = false;
            }

            generateAnimate(frontView, swap, swapRight, downPosition, deltaX);

            velocityTracker.recycle();
            velocityTracker = null;
            downX = 0;
            swiping = false;
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            if (velocityTracker == null || paused || downPosition == ListView.INVALID_POSITION) {
                break;
            }

            velocityTracker.addMovement(motionEvent);
            velocityTracker.computeCurrentVelocity(1000);
            float velocityX = Math.abs(velocityTracker.getXVelocity());
            float velocityY = Math.abs(velocityTracker.getYVelocity());
            float deltaX = motionEvent.getRawX() - downX;

            if ((deltaX > slop) && swipeCurrentAction == SwipeListView.SWIPE_ACTION_REVEAL
                    && velocityY < velocityX) {
                swiping = true;
                swipingRight = (deltaX > 0);
                if (SwipeListView.DEBUG) {
                    Log.d(SwipeListView.TAG, "deltaX: " + deltaX + " - swipingRight: " + swipingRight);
                }
                swipeCurrentAction = SwipeListView.SWIPE_ACTION_REVEAL;
                swipeListView.requestDisallowInterceptTouchEvent(true);
                MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
                cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (MotionEventCompat
                        .getActionIndex(motionEvent) << MotionEventCompat.ACTION_POINTER_INDEX_SHIFT));
                swipeListView.onTouchEvent(cancelEvent);
                if (swipeCurrentAction == SwipeListView.SWIPE_ACTION_REVEAL) {
                    backView.setVisibility(View.VISIBLE);
                }
            }
            break;
        }
        }
        return false;
    }

}