帮助解决Android UI ListView问题

Jux*_*ion 5 android drag-and-drop highlighting android-listview

要理解这个问题,首先要阅读此方法的工作原理.

我正在尝试实现拖放ListView,它没有问题,但已经遇到了障碍.所以,我没有处理的一切,我拦截(但返回false)MotionEvents发送到ListView,让它处理滚动之类的东西.当我想开始拖动一个项目时,我返回true并处理所有拖动的东西.除了一件事,一切都很好.当确定长按(在onInterceptTouchEvent中)时,启动拖动(拖放).我得到了像我这样拖动的图像的Bitmap.itemPositition是所选项目的索引.

(省略不相关的部分)

...
View dragItem = mListView.getChildAt(itemPosition);
dragItem.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(dragItem.getDrawingCache());
mDragImage = new ImageView(mContext);
mDragImage.setImageBitmap(bitmap);
...
Run Code Online (Sandbox Code Playgroud)

问题是,mDragImage是一个像这样的纯黑色. 一个可靠的后位图

但是,如果我不让ListView处理任何事情.就像在,我开始在ACTION_DOWN上拖动并在ACTION_UP上停止,mDragImage看起来已经预期(但我显然失去了滚动功能).

一个好的位图

由于拖动是通过长按开始的,因此ListView有机会在长按之前执行操作.这是我猜测为什么会发生这种情况的原因.按下某个项目时,ListView会突出显示该项目.在这样做的某个地方,它正在搞乱位图.因此,当我去获取它时,它处于一种奇怪的状态(全黑).

我看到两种解决这个问题的方法,我都不知道怎么做.

  1. 从头开始创建图像.

  2. 自己处理突出显示(如果这是问题).

对我来说,选项二似乎更好,除了我查看了文档和源代码,但无法找到如何执行此操作.以下是我做过/试过的一些事情.

  • 我用一个空方法设置setOnItemClickListener(...)setOnItemSelectedListener(...)(突出显示仍然发生).(在任何人建议之前,调用 setOnClickListener会导致运行时错误.)

  • 我还试图让ListView创建一个新项目(对于选项2),但找不到方法.

  • 花了45分钟查看源代码和文档,试图找出突出显示的位置(我从未找到它).

任何帮助解决这个问题将不胜感激.

(EDIT1 START)

所以我实际上并不知道onLongClickListener是否正常工作,我在思考它之前犯了一个错误.我正在尝试立即设置它,当我发现它是否确实时会更新.

(EDIT1 END)

发布前的最后一分钟编辑.我刚刚尝试使用onLongClickListener,图像很好.我还是想知道是否还有其他办法.我如何使用onLongClickListener来使事情工作是丑陋的,但它的工作原理.我也花了很多时间试图解决这个问题,找到答案会很高兴.我仍然希望能够更改/处理高光颜色,默认的橙色颜色并不漂亮.哦,抱歉帖子的长度.我想不出让它缩短的方法,同时提供我认为需要的所有信息.

小智 0

使用此代码,它允许在 ListView 中操作药物和放置:

public class DraggableListView extends ListView {

    private static final String LOG_TAG = "tasks365";

    private static final int END_OF_LIST_POSITION = -2;

    private DropListener mDropListener;
    private int draggingItemHoverPosition;
    private int dragStartPosition; // where was the dragged item originally
    private int mUpperBound; // scroll the view when dragging point is moving out of this bound
    private int mLowerBound; // scroll the view when dragging point is moving out of this bound
    private int touchSlop;
    private Dragging dragging;
    private GestureDetector longPressDetector;

    public DraggableListView(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.listViewStyle);
    }

    public DraggableListView(final Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

        longPressDetector = new GestureDetector(getContext(), new SimpleOnGestureListener() {
            @Override
            public void onLongPress(final MotionEvent e) {
                int x = (int) e.getX();
                final int y = (int) e.getY();

                int itemnum = pointToPosition(x, y);
                if (itemnum == AdapterView.INVALID_POSITION) {
                    return;
                }

                if (dragging != null) {
                    dragging.stop();
                    dragging = null;
                }

                final View item = getChildAt(itemnum - getFirstVisiblePosition());
                item.setPressed(false);
                dragging = new Dragging(getContext());
                dragging.start(y, ((int) e.getRawY()) - y, item);
                draggingItemHoverPosition = itemnum;
                dragStartPosition = draggingItemHoverPosition;

                int height = getHeight();
                mUpperBound = Math.min(y - touchSlop, height / 3);
                mLowerBound = Math.max(y + touchSlop, height * 2 / 3);
            }
        });

        setOnItemLongClickListener(new OnItemLongClickListener() {
            @SuppressWarnings("unused")

            public boolean onItemLongClick(AdapterView<?> paramAdapterView, View paramView, int paramInt, long paramLong) {
                // Return true to let AbsListView reset touch mode
                // Without this handler, the pressed item will keep highlight.
                return true;
            }
        });
    }

    /* pointToPosition() doesn't consider invisible views, but we need to, so implement a slightly different version. */
    private int myPointToPosition(int x, int y) {
        if (y < 0) {
            return getFirstVisiblePosition();
        }
        Rect frame = new Rect();
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            child.getHitRect(frame);
            if (frame.contains(x, y)) {
                return getFirstVisiblePosition() + i;
            }
        }
        if ((x >= frame.left) && (x < frame.right) && (y >= frame.bottom)) {
            return END_OF_LIST_POSITION;
        }
        return INVALID_POSITION;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (longPressDetector.onTouchEvent(ev)) {
            return true;
        }

        if ((dragging == null) || (mDropListener == null)) {
            // it is not dragging, or there is no drop listener
            return super.onTouchEvent(ev);
        }

        int action = ev.getAction();
        switch (ev.getAction()) {

        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            dragging.stop();
            dragging = null;

            if (mDropListener != null) {
                if (draggingItemHoverPosition == END_OF_LIST_POSITION) {
                    mDropListener.drop(dragStartPosition, getCount() - 1);
                } else if (draggingItemHoverPosition != INVALID_POSITION) {
                    mDropListener.drop(dragStartPosition, draggingItemHoverPosition);
                }
            }
            resetViews();
            break;

        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            int x = (int) ev.getX();
            int y = (int) ev.getY();
            dragging.drag(x, y);
            int position = dragging.calculateHoverPosition();
            if (position != INVALID_POSITION) {
                if ((action == MotionEvent.ACTION_DOWN) || (position != draggingItemHoverPosition)) {
                    draggingItemHoverPosition = position;
                    doExpansion();
                }
                scrollList(y);
            }
            break;
        }
        return true;
    }

    private void doExpansion() {
        int expanItemViewIndex = draggingItemHoverPosition - getFirstVisiblePosition();
        if (draggingItemHoverPosition >= dragStartPosition) {
            expanItemViewIndex++;
        }

       // Log.v(LOG_TAG, "Dragging item hovers over position " + draggingItemHoverPosition + ", expand item at index "
         //       + expanItemViewIndex);

        View draggingItemOriginalView = getChildAt(dragStartPosition - getFirstVisiblePosition());
        for (int i = 0;; i++) {
            View itemView = getChildAt(i);
            if (itemView == null) {
                break;
            }
            ViewGroup.LayoutParams params = itemView.getLayoutParams();
            int height = LayoutParams.WRAP_CONTENT;
            if (itemView.equals(draggingItemOriginalView)) {
                height = 1;
            } else if (i == expanItemViewIndex) {
                height = itemView.getHeight() + dragging.getDraggingItemHeight();
            }
            params.height = height;
            itemView.setLayoutParams(params);
        }
    }

    /**
     * Reset view to original height.
     */
    private void resetViews() {
        for (int i = 0;; i++) {
            View v = getChildAt(i);
            if (v == null) {
                layoutChildren(); // force children to be recreated where needed
                v = getChildAt(i);
                if (v == null) {
                    break;
                }
            }
            ViewGroup.LayoutParams params = v.getLayoutParams();
            params.height = LayoutParams.WRAP_CONTENT;
            v.setLayoutParams(params);
        }
    }

    private void resetScrollBounds(int y) {
        int height = getHeight();
        if (y >= height / 3) {
            mUpperBound = height / 3;
        }
        if (y <= height * 2 / 3) {
            mLowerBound = height * 2 / 3;
        }
    }

    private void scrollList(int y) {
        resetScrollBounds(y);

        int height = getHeight();
        int speed = 0;
        if (y > mLowerBound) {
            // scroll the list up a bit
            speed = y > (height + mLowerBound) / 2 ? 16 : 4;
        } else if (y < mUpperBound) {
            // scroll the list down a bit
            speed = y < mUpperBound / 2 ? -16 : -4;
        }
        if (speed != 0) {
            int ref = pointToPosition(0, height / 2);
            if (ref == AdapterView.INVALID_POSITION) {
                //we hit a divider or an invisible view, check somewhere else
                ref = pointToPosition(0, height / 2 + getDividerHeight() + 64);
            }
            View v = getChildAt(ref - getFirstVisiblePosition());
            if (v != null) {
                int pos = v.getTop();
                setSelectionFromTop(ref, pos - speed);
            }
        }
    }

    public void setDropListener(DropListener l) {
        mDropListener = l;
    }

    public interface DropListener {
        void drop(int from, int to);
    }

    class Dragging {

        private Context context;
        private WindowManager windowManager;
        private WindowManager.LayoutParams mWindowParams;
        private ImageView mDragView;
        private Bitmap mDragBitmap;
        private int coordOffset;
        private int mDragPoint; // at what offset inside the item did the user grab it
        private int draggingItemHeight;
        private int x;
        private int y;
        private int lastY;

        public Dragging(Context context) {
            this.context = context;
            windowManager = (WindowManager) context.getSystemService("window");
        }

        /**
         * @param y
         * @param offset - the difference in y axis between screen coordinates and coordinates in this view
         * @param view - which view is dragged
         */
        public void start(int y, int offset, View view) {
            this.y = y;
            lastY = y;
            this.coordOffset = offset;
            mDragPoint = y - view.getTop();

            draggingItemHeight = view.getHeight();

            mDragView = new ImageView(context);
            mDragView.setBackgroundResource(android.R.drawable.alert_light_frame);

            // Create a copy of the drawing cache so that it does not get recycled
            // by the framework when the list tries to clean up memory
            view.setDrawingCacheEnabled(true);
            mDragBitmap = Bitmap.createBitmap(view.getDrawingCache());
            mDragView.setImageBitmap(mDragBitmap);

            mWindowParams = new WindowManager.LayoutParams();
            mWindowParams.gravity = Gravity.TOP;
            mWindowParams.x = 0;
            mWindowParams.y = y - mDragPoint + coordOffset;
            mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
            mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
            mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
            mWindowParams.format = PixelFormat.TRANSLUCENT;
            mWindowParams.windowAnimations = 0;

            windowManager.addView(mDragView, mWindowParams);
        }

        public void drag(int x, int y) {
            lastY = this.y;
            this.x = x;
            this.y = y;
            mWindowParams.y = y - mDragPoint + coordOffset;
            windowManager.updateViewLayout(mDragView, mWindowParams);
        }

        public void stop() {
            if (mDragView != null) {
                windowManager.removeView(mDragView);
                mDragView.setImageDrawable(null);
                mDragView = null;
            }
            if (mDragBitmap != null) {
                mDragBitmap.recycle();
                mDragBitmap = null;
            }
        }

        public int getDraggingItemHeight() {
            return draggingItemHeight;
        }

        public int calculateHoverPosition() {
            int adjustedY = (int) (y - mDragPoint + (Math.signum(y - lastY) + 2) * draggingItemHeight / 2);
            // Log.v(LOG_TAG, "calculateHoverPosition(): lastY=" + lastY + ", y=" + y + ", adjustedY=" + adjustedY);
            int pos = myPointToPosition(0, adjustedY);
            if (pos >= 0) {
                if (pos >= dragStartPosition) {
                    pos -= 1;
                }
            }
            return pos;
        }

    }
}
Run Code Online (Sandbox Code Playgroud)