Android列表项滑动

48

有没有一个简单的ListActivity示例,可以在一列中显示Textviews,当你从左往右滑动时,你会看到该行在一个新的视图中?这是为了编辑该行的数据或显示更详细的信息。请不要引用code shogun或其他网站,因为我已经谷歌搜索过,并没有找到答案。


我已经在使用上下文菜单来更改字体大小,并且为其他活动设置长按。我想让用户能够向左滑动打开完整的数据屏幕,以查看他们滑动的行。 - JPM
我猜现在碎片可以解决这个问题了。 - JPM
4个回答

117

我也遇到了同样的问题,但是在这里没找到答案。

我想在ListView项中检测滑动操作并标记它为已滑动,同时继续支持OnItemClick和OnItemLongClick事件。

下面是我的解决方案:

第一步:SwipeDetector类:

import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class SwipeDetector implements View.OnTouchListener {

    public static enum Action {
        LR, // Left to Right
        RL, // Right to Left
        TB, // Top to bottom
        BT, // Bottom to Top
        None // when no action was detected
    }

    private static final String logTag = "SwipeDetector";
    private static final int MIN_DISTANCE = 100;
    private float downX, downY, upX, upY;
    private Action mSwipeDetected = Action.None;

    public boolean swipeDetected() {
        return mSwipeDetected != Action.None;
    }

    public Action getAction() {
        return mSwipeDetected;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downX = event.getX();
            downY = event.getY();
            mSwipeDetected = Action.None;
            return false; // allow other events like Click to be processed
        case MotionEvent.ACTION_UP:
            upX = event.getX();
            upY = event.getY();

            float deltaX = downX - upX;
            float deltaY = downY - upY;

            // horizontal swipe detection
            if (Math.abs(deltaX) > MIN_DISTANCE) {
                // left or right
                if (deltaX < 0) {
                    Log.i(logTag, "Swipe Left to Right");
                    mSwipeDetected = Action.LR;
                    return false;
                }
                if (deltaX > 0) {
                    Log.i(logTag, "Swipe Right to Left");
                    mSwipeDetected = Action.RL;
                    return false;
                }
            } else if (Math.abs(deltaY) > MIN_DISTANCE) { // vertical swipe
                                                            // detection
                // top or down
                if (deltaY < 0) {
                    Log.i(logTag, "Swipe Top to Bottom");
                    mSwipeDetected = Action.TB;
                    return false;
                }
                if (deltaY > 0) {
                    Log.i(logTag, "Swipe Bottom to Top");
                    mSwipeDetected = Action.BT;
                    return false;
                }
            }
            return false;
        }
        return false;
    }
}

第二步,我在列表视图中使用滑动检测器类:

    final ListView lv = getListView();
    final SwipeDetector swipeDetector = new SwipeDetector();
    lv.setOnTouchListener(swipeDetector);
    lv.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (swipeDetector.swipeDetected()){
                    // do the onSwipe action 
                } else {
                    // do the onItemClick action
                }
            }
    });
    lv.setOnItemLongClickListener(new OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {
            if (swipeDetector.swipeDetected()){
                // do the onSwipe action 
            } else {
                // do the onItemLongClick action
            }
        }
    });
这样我就可以支持3种操作方式-滑动、点击和长按,并且我可以使用ListView item info。
ADDED LATER: 由于ListView会捕获滚动操作,有时候很难进行滑动操作。为了解决这个问题,我对SwipeDetector.onTouch进行了以下更改:
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            downX = event.getX();
            downY = event.getY();
            mSwipeDetected = Action.None;
            return false; // allow other events like Click to be processed
        }
        case MotionEvent.ACTION_MOVE: {
            upX = event.getX();
            upY = event.getY();

            float deltaX = downX - upX;
            float deltaY = downY - upY;

            // horizontal swipe detection
            if (Math.abs(deltaX) > HORIZONTAL_MIN_DISTANCE) {
                // left or right
                if (deltaX < 0) {
                    Log.i(logTag, "Swipe Left to Right");
                    mSwipeDetected = Action.LR;
                    return true;
                }
                if (deltaX > 0) {
                    Log.i(logTag, "Swipe Right to Left");
                    mSwipeDetected = Action.RL;
                    return true;
                }
            } else 

            // vertical swipe detection
            if (Math.abs(deltaY) > VERTICAL_MIN_DISTANCE) {
                // top or down
                if (deltaY < 0) {
                    Log.i(logTag, "Swipe Top to Bottom");
                    mSwipeDetected = Action.TB;
                    return false;
                }
                if (deltaY > 0) {
                    Log.i(logTag, "Swipe Bottom to Top");
                    mSwipeDetected = Action.BT;
                    return false;
                }
            } 
            return true;
        }
    }
    return false;
}

1
HORIZONTAL_MIN_DISTANCE和VERTICAL_MIN_DISTANCE是用户手指移动的最小距离,以便将其视为滑动操作。 我将其设置为:HORIZONTAL_MIN_DISTANCE = 40; VERTICAL_MIN_DISTANCE = 80; - Asaf Pinhassi
为什么在OnItemClick或setOnItemLongClickListener中不能处理从上到下的滑动?敬礼 - onder
这是一个很棒的教程!我该如何让用户滑动并提供删除选项?因此,他们可以通过滑动来删除,然后会出现一个按钮供按下以进行删除操作? - Si8
1
请纠正我,但是应该使用DP值来设置HORIZONTAL_MIN_DISTANCE和VERTICAL_MIN_DISTANCE。这样可以为这个类提供未来的支持(适用于超高分辨率的手机和平板电脑)。 - Oliver Dixon
1
这很不错啊,唯一的问题是它不够灵敏。我需要先长按选项卡,然后才能滑动。而且大多数情况下,它甚至无法识别我的滑动操作。有更好的解决方案吗? - Gofilord
显示剩余9条评论

1
这里是一个非常简化的版本,使用两个监听器(onTouch用于检测滑动,onClickItem用于检测项目点击),使用isSwipe标志来阻止onClickItemListener,直到确认它不是滑动。
检测点击时,首先考虑它不是滑动。
        listView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
            {
                if(!isSwipe)
                {
                    adapter.increase(arg2);
                    adapter.notifyDataSetChanged();
                }
            }
        });

检测滑动。
        listView.setOnTouchListener(new OnTouchListener() {
        private int action_down_x = 0;
            private int action_up_x = 0;
            private int difference = 0;
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        action_down_x = (int) event.getX();
                        isSwipe=false;  //until now
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if(!isSwipe)
                        {
                            action_up_x = (int) event.getX();
                            difference = action_down_x - action_up_x;
                            if(Math.abs(difference)>50)
                            {
                                Log.d("action","action down x: "+action_down_x);
                                Log.d("action","action up x: "+action_up_x);
                                Log.d("action","difference: "+difference);
                                //swipe left or right
                                if(difference>0){
                                    //swipe left
                                    Log.d("action","swipe left");
                                    adapter.decrease(selectedItem);
                                    adapter.notifyDataSetChanged();
                                }
                                else{
                                    //swipe right
                                    Log.d("action","swipe right");
                                }
                                isSwipe=true;
                            }
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        Log.d("action", "ACTION_UP - ");
                        action_down_x = 0;
                        action_up_x = 0;
                        difference = 0;
                        break;
                }
                return false;   //to allow the clicklistener to work after
            }
        })

1

这是我用来检测滑动手势的片段。然后你可以使用 viewflipper 来改变视图。

  @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (gestureDetector.onTouchEvent(event)) {
                return true;
            } else {
                return false;
            }
        }

        private static final int SWIPE_MIN_DISTANCE = 30;
        private static final int SWIPE_MAX_OFF_PATH = 250;
        private static final int SWIPE_THRESHOLD_VELOCITY = 200;
        class MyGestureDetector extends SimpleOnGestureListener {
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                    float velocityY) {
                try {
                    if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                        return false;
                    // right to left swipe
                    if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
                            && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                        leftFling();
                    } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                            && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                        rightFling();
                    }
                } catch (Exception e) {
                    // nothing
                }
                return false;
            }

        }

我更想要一个完美的例子。我尝试过ViewFlippers,但是当你这样做时,列表大小总是有些奇怪。不过我很喜欢你的代码,它非常干净。我将在未来的尝试中使用它,谢谢。 - JPM

0

如果你想在列表项滑动时显示一些带有操作的按钮,互联网上有很多具有此行为的库。

我实现了我在互联网上找到的库,非常满意。它非常简单易用且速度非常快。我改进了原始库,并添加了一个新的点击监听器以进行项目点击。此外,我还添加了字体awesome库(http://fortawesome.github.io/Font-Awesome/),现在您可以轻松地添加新的项目标题并指定来自字体awesome的图标名称。

这里是github链接


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接