web-dev-qa-db-fra.com

Android - ListView glisser vers la gauche / droite comme Samsung contacte ListView

Je développe une application et j'ai besoin d'un ListView comme ListView conctact de mon Samsung Galaxy S:

img

Lorsque je fais glisser mon doigt vers la droite, je peux envoyer un message à ce contact.

Lorsque je fais glisser mon doigt vers la droite, je peux appeler mon contact.

J'ai ma ListView et je n'ai besoin que de la fonction pour le faire ...

Merci d'avance.

PD: J'ai beaucoup cherché et je n'ai rien trouvé. Les plus similaires: Ressource pour Android Légère action de diapositive gauche/droite sur listview

30
Oliver

Ce que vous pourriez faire ici, c'est créer une nouvelle vue spécialement pour la vue de liste (appelez-la ListViewFlinger ou quelque chose). Ensuite, dans cette vue, remplacez sa méthode onTouchEvent et placez-y du code pour déterminer un mouvement de diapositive. Une fois que vous avez le geste de diapositive, déclenchez un événement onSlideComplete (vous devrez faire de cet auditeur) un voialla, vous un ListView avec un contenu activé par diapositive.

float historicX = Float.NaN, historicY = Float.NaN;
static final TRIGGER_DELTA = 50; // Number of pixels to travel till trigger

@Override public boolean onTouchEvent(MotionEvent e) {

    switch (e.getAction()) {
    case MotionEvent.ACTION_DOWN:
        historicX = e.getX();
        historicY = e.getY();
        break;
    case MotionEvent.ACTION_UP:
        if (e.getX() - historicX > -TRIGGER_DELTA) {
            onSlideComplete(Direction.LEFT);
            return true;
        }
        else if (e.getX() - historicX > TRIGGER_DELTA)  {
            onSlideComplete(Direction.RIGHT);
            return true;
        } break;
    default:
        return super.onTouchEvent(e);
    }
}

enum Direction {
    LEFT, RIGHT;
}

interface OnSlideCompleteListener {
    void onSlideComplete(Direction dir);
}
18
ahodder

À partir d'un autre post, il y avait un lien vers ce code Google: https://Gist.github.com/298059 Qui proviennent de ce post Google+: https://plus.google. com/u/0/113735310430199015092/messages/Fgo1p5uWZL . Il s'agit d'une fonctionnalité Swipe-To-Dismiss.

À partir de cela, vous pouvez fournir votre propre code Swipe-To-Action. Voici donc ma version, où je peux personnaliser l'action gauche et droite et vous pouvez déclencher l'animation Dismiss (ce n'est qu'une modification du code de Roman Nuric).

Vous devez inclure cette classe dans votre projet:

public class SwipeListViewTouchListener implements View.OnTouchListener {
    // 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 OnSwipeCallback mCallback;
    private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
    private boolean dismissLeft = true;
    private boolean dismissRight = true;

    // Transient properties
    private List < PendingSwipeData > mPendingSwipes = new ArrayList < PendingSwipeData > ();
    private int mDismissAnimationRefCount = 0;
    private float mDownX;
    private boolean mSwiping;
    private VelocityTracker mVelocityTracker;
    private int mDownPosition;
    private View mDownView;
    private boolean mPaused;

    /**
     * The callback interface used by {@link SwipeListViewTouchListener} to inform its client
     * about a successful swipe of one or more list item positions.
     */
    public interface OnSwipeCallback {
        /**
         * Called when the user has swiped the list item to the left.
         *
         * @param listView               The originating {@link ListView}.
         * @param reverseSortedPositions An array of positions to dismiss, sorted in descending
         *                               order for convenience.
         */
        void onSwipeLeft(ListView listView, int[] reverseSortedPositions);

        void onSwipeRight(ListView listView, int[] reverseSortedPositions);
    }

    /**
     * Constructs a new swipe-to-action touch listener for the given list view.
     *
     * @param listView The list view whose items should be dismissable.
     * @param callback The callback to trigger when the user has indicated that she would like to
     *                 dismiss one or more list items.
     */
    public SwipeListViewTouchListener(ListView listView, OnSwipeCallback callback) {
        ViewConfiguration vc = ViewConfiguration.get(listView.getContext());
        mSlop = vc.getScaledTouchSlop();
        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
        mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
        mAnimationTime = listView.getContext().getResources().getInteger(
            Android.R.integer.config_shortAnimTime);
        mListView = listView;
        mCallback = callback;
    }

    /**
     * Constructs a new swipe-to-action touch listener for the given list view.
     * 
     * @param listView The list view whose items should be dismissable.
     * @param callback The callback to trigger when the user has indicated that she would like to
     *                 dismiss one or more list items.
     * @param dismissLeft set if the dismiss animation is up when the user swipe to the left
     * @param dismissRight set if the dismiss animation is up when the user swipe to the right
     * @see #SwipeListViewTouchListener(ListView, OnSwipeCallback, boolean, boolean)
     */
    public SwipeListViewTouchListener(ListView listView, OnSwipeCallback callback, boolean dismissLeft, boolean dismissRight) {
        this(listView, callback);
        this.dismissLeft = dismissLeft;
        this.dismissRight = dismissRight;
    }

    /**
     * Enables or disables (pauses or resumes) watching for swipe-to-dismiss gestures.
     *
     * @param enabled Whether or not to watch for gestures.
     */
    public void setEnabled(boolean enabled) {
        mPaused = !enabled;
    }

    /**
     * Returns an {@link Android.widget.AbsListView.OnScrollListener} to be added to the
     * {@link ListView} using
     * {@link ListView#setOnScrollListener(Android.widget.AbsListView.OnScrollListener)}.
     * If a scroll listener is already assigned, the caller should still pass scroll changes
     * through to this listener. This will ensure that this
     * {@link SwipeListViewTouchListener} is paused during list view scrolling.</p>
     *
     * @see {@link SwipeListViewTouchListener}
     */
    public AbsListView.OnScrollListener makeScrollListener() {
        return new AbsListView.OnScrollListener() {@
            Override
            public void onScrollStateChanged(AbsListView absListView, int scrollState) {
                setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
            }

            @
            Override
            public void onScroll(AbsListView absListView, int i, int i1, int i2) {}
        };
    }

    @
    Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (mViewWidth < 2) {
            mViewWidth = mListView.getWidth();
        }

        switch (motionEvent.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            {
                if (mPaused) {
                    return false;
                }

                // TODO: ensure this is a finger, and set a flag

                // Find the child view that was touched (perform a hit test)
                Rect rect = new Rect();
                int childCount = mListView.getChildCount();
                int[] listViewCoords = new int[2];
                mListView.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 = mListView.getChildAt(i);
                    child.getHitRect(rect);
                    if (rect.contains(x, y)) {
                        mDownView = child;
                        break;
                    }
                }

                if (mDownView != null) {
                    mDownX = motionEvent.getRawX();
                    mDownPosition = mListView.getPositionForView(mDownView);

                    mVelocityTracker = VelocityTracker.obtain();
                    mVelocityTracker.addMovement(motionEvent);
                }
                view.onTouchEvent(motionEvent);
                return true;
            }

        case MotionEvent.ACTION_UP:
            {
                if (mVelocityTracker == null) {
                    break;
                }

                float deltaX = motionEvent.getRawX() - mDownX;
                mVelocityTracker.addMovement(motionEvent);
                mVelocityTracker.computeCurrentVelocity(500); // 1000 by defaut but it was too much
                float velocityX = Math.abs(mVelocityTracker.getXVelocity());
                float velocityY = Math.abs(mVelocityTracker.getYVelocity());
                boolean swipe = false;
                boolean swipeRight = false;

                if (Math.abs(deltaX) > mViewWidth / 2) {
                    swipe = true;
                    swipeRight = deltaX > 0;
                } else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity && velocityY < velocityX) {
                    swipe = true;
                    swipeRight = mVelocityTracker.getXVelocity() > 0;
                }
                if (swipe) {
                    // sufficent swipe value
                    final View downView = mDownView; // mDownView gets null'd before animation ends
                    final int downPosition = mDownPosition;
                    final boolean toTheRight = swipeRight;
                    ++mDismissAnimationRefCount;
                    mDownView.animate()
                        .translationX(swipeRight ? mViewWidth : -mViewWidth)
                        .alpha(0)
                        .setDuration(mAnimationTime)
                        .setListener(new AnimatorListenerAdapter() {@
                        Override
                        public void onAnimationEnd(Animator animation) {
                            performSwipeAction(downView, downPosition, toTheRight, toTheRight ? dismissRight : dismissLeft);
                        }
                    });
                } else {
                    // cancel
                    mDownView.animate()
                        .translationX(0)
                        .alpha(1)
                        .setDuration(mAnimationTime)
                        .setListener(null);
                }
                mVelocityTracker = null;
                mDownX = 0;
                mDownView = null;
                mDownPosition = ListView.INVALID_POSITION;
                mSwiping = false;
                break;
            }

        case MotionEvent.ACTION_MOVE:
            {
                if (mVelocityTracker == null || mPaused) {
                    break;
                }

                mVelocityTracker.addMovement(motionEvent);
                float deltaX = motionEvent.getRawX() - mDownX;
                if (Math.abs(deltaX) > mSlop) {
                    mSwiping = true;
                    mListView.requestDisallowInterceptTouchEvent(true);

                    // Cancel ListView's touch (un-highlighting the item)
                    MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
                    cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
                        (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
                    mListView.onTouchEvent(cancelEvent);
                }

                if (mSwiping) {
                    mDownView.setTranslationX(deltaX);
                    mDownView.setAlpha(Math.max(0f, Math.min(1f,
                        1f - 2f * Math.abs(deltaX) / mViewWidth)));
                    return true;
                }
                break;
            }
        }
        return false;
    }

    class PendingSwipeData implements Comparable < PendingSwipeData > {
        public int position;
        public View view;

        public PendingSwipeData(int position, View view) {
            this.position = position;
            this.view = view;
        }

        @
        Override
        public int compareTo(PendingSwipeData other) {
            // Sort by descending position
            return other.position - position;
        }
    }

    private void performSwipeAction(final View swipeView, final int swipePosition, boolean toTheRight, boolean dismiss) {
        // 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 = swipeView.getLayoutParams();
        final int originalHeight = swipeView.getHeight();
        final boolean swipeRight = toTheRight;

        ValueAnimator animator;
        if (dismiss)
            animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
        else
            animator = ValueAnimator.ofInt(originalHeight, 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(mPendingSwipes);

                    int[] swipePositions = new int[mPendingSwipes.size()];
                    for (int i = mPendingSwipes.size() - 1; i >= 0; i--) {
                        swipePositions[i] = mPendingSwipes.get(i).position;
                    }
                    if (swipeRight)
                        mCallback.onSwipeRight(mListView, swipePositions);
                    else
                        mCallback.onSwipeLeft(mListView, swipePositions);

                    ViewGroup.LayoutParams lp;
                    for (PendingSwipeData pendingDismiss: mPendingSwipes) {
                        // Reset view presentation
                        pendingDismiss.view.setAlpha(1f);
                        pendingDismiss.view.setTranslationX(0);
                        lp = pendingDismiss.view.getLayoutParams();
                        lp.height = originalHeight;
                        pendingDismiss.view.setLayoutParams(lp);
                    }

                    mPendingSwipes.clear();
                }
            }
        });

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@
            Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                lp.height = (Integer) valueAnimator.getAnimatedValue();
                swipeView.setLayoutParams(lp);
            }
        });

        mPendingSwipes.add(new PendingSwipeData(swipePosition, swipeView));
        animator.start();
    }
}

De là, vous pouvez ajouter le code suivant à votre onCreate dans l'activité avec ListView:

// Create a ListView-specific touch listener. ListViews are given special treatment because
// by default they handle touches for their list items... i.e. they're in charge of drawing
// the pressed state (the list selector), handling list item clicks, etc.
SwipeListViewTouchListener touchListener =
    new SwipeListViewTouchListener(
        listView,
        new SwipeListViewTouchListener.OnSwipeCallback() {
            @Override
            public void onSwipeLeft(ListView listView, int [] reverseSortedPositions) {
                //  Log.i(this.getClass().getName(), "swipe left : pos="+reverseSortedPositions[0]);
                // TODO : YOUR CODE HERE FOR LEFT ACTION
            }

            @Override
            public void onSwipeRight(ListView listView, int [] reverseSortedPositions) {
                //  Log.i(ProfileMenuActivity.class.getClass().getName(), "swipe right : pos="+reverseSortedPositions[0]);
                // TODO : YOUR CODE HERE FOR RIGHT ACTION
            }
        },
        true, // example : left action = dismiss
        false); // example : right action without dismiss animation
listView.setOnTouchListener(touchListener);
// Setting this scroll listener is required to ensure that during ListView scrolling,
// we don't look for swipes.
listView.setOnScrollListener(touchListener.makeScrollListener());

Modifier: pour ajouter une modification de couleur lors du glissement, votre code doit être dans le case MotionEvent.ACTION_MOVE près de mDownView.setAlpha.

28
Solostaran14

Si vous souhaitez effectuer une action On Swiping:

Extraire SwipeActionAdapter

C'est une bibliothèque impressionnante qui permet de glisser dans les deux directions avec un Layout ou Color sous-jacent, et effectue l'action souhaitée lorsque le geste de glisser/glisser est terminé. Vous pouvez le configurer pour révéler/modifier la disposition.

~ Je n'ai pas utilisé l'application Samsung Contacts, mais cela ressemble à ce que vous voulez

Left SwipeRight Swipe


Si vous souhaitez glisser vers Révéler boutons actionnables:

Découvrez SwipeMenuListView

Dans un sens, cela ressemble plus à la TableViews Swipe-able dans iOS.

SwipeMenuListViewSwipeMenuListViewSwipeMenuListView

1
Sheharyar