0

修正方法がわからないバグがあります。要点は、リストビューに DragNDrop 機能を実装する必要があるが、minSdkVersion="7" を実装する必要があるため、Eric Harlowのフレームワークを使用したことです。

Android 2.1、2.2、2.3.6 から 4.0 まではすべて正常に動作しましたが、Android 4.1.2 でアプリをテストするとバグが発生しました。問題の核心は次のとおりです。リストビューに 4 つの項目が含まれており、4 番目の項目を 3 番目の位置にドラッグしているとします。

私がそれをやったら、4つのアイテムをおそらく2つの位置にドラッグしたいと思います。初めて 4 位から 3 位にドラッグ アンド ドロップしたとき、結果は OK で、ビューが無効になりました。しかし、4 番目のアイテムを 2 回目にドラッグ アンド ドロップしたい場合、指の下に古い 4 番目の要素 (現在は 3 要素) があり、新しい要素ではありません。

私の調査では、ビューオブジェクトを移動しようとしたときにビューオブジェクトへの参照が間違っていましたが、View item = getChildAt(itemIndex);Android 初期の 4.1.2 で完全に動作し、Android 4.1.2 でバグを処理する理由がわかりません。

誰かがこのバグを修正する方法を知っていますか?

以下はコードのレビューです。

 public class DragNDropListView extends ListView {

    private static final int OUR_LOCATION_ELEMENT = 1;
    private static final int MIN_INDEX_ELEM_DONT_TOUCH = 2;
    boolean mDragMode;

    int mStartPosition;
    int mEndPosition;
    int mDragPointOffset;       //Used to adjust drag view location

    ImageView mDragView;

    DropListener mDropListener;
    RemoveListener mRemoveListener;
    DragListener mDragListener;
    UpdateOurLocationListener mOnClickListener;

    Context context;

    public DragNDropListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

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

    public void setRemoveListener(RemoveListener l) {
        mRemoveListener = l;
    }

    public void setDragListener(DragListener l) {
        mDragListener = l;
    }

    public void setOnOurLocationListener (UpdateOurLocationListener l) {
        mOnClickListener = l;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        final int x = (int) ev.getX();
        final int y = (int) ev.getY();  

        if (action == MotionEvent.ACTION_DOWN &&
                x > (this.getWidth()-context.getResources().getDimension(R.dimen.image_move_width))&&
                pointToPosition(x,y) == OUR_LOCATION_ELEMENT) {
                mOnClickListener.onOurLocationClick();
                mDragMode = false;
        }

        if (action == MotionEvent.ACTION_DOWN &&
            x > (this.getWidth()-context.getResources().getDimension(R.dimen.image_move_width))&&
            pointToPosition(x,y)>MIN_INDEX_ELEM_DONT_TOUCH) {
            mDragMode = true;
        }

        if (!mDragMode) 
            return super.onTouchEvent(ev);

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mStartPosition = pointToPosition(x,y);
                if (mStartPosition != INVALID_POSITION) {
                    int mItemPosition = mStartPosition - getFirstVisiblePosition();
                    mDragPointOffset = y - getChildAt(mItemPosition).getTop();
                    mDragPointOffset -= ((int)ev.getRawY()) - y;
                    startDrag(mItemPosition,y);

                    drag(0,y);// replace 0 with x if desired
                }   
                break;
            case MotionEvent.ACTION_MOVE:
                drag(0,y);// replace 0 with x if desired
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
            default:
                mDragMode = false;
                mEndPosition = pointToPosition(x,y);
                stopDrag(mStartPosition - getFirstVisiblePosition());
                if (mDropListener != null && mStartPosition != INVALID_POSITION 
                        && mEndPosition != INVALID_POSITION 
                        && mEndPosition > MIN_INDEX_ELEM_DONT_TOUCH) {
                    mDropListener.onDrop(mStartPosition, mEndPosition);
                }
                break;
        }
        return true;
    }   

    // move the drag view
    private void drag(int x, int y) {
        if (mDragView != null) {
            WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mDragView.getLayoutParams();
            layoutParams.x = x;
            layoutParams.y = y - mDragPointOffset;
            WindowManager mWindowManager = (WindowManager) getContext()
                    .getSystemService(Context.WINDOW_SERVICE);
            mWindowManager.updateViewLayout(mDragView, layoutParams);

            if (mDragListener != null)
                mDragListener.onDrag(x, y, null);// change null to "this" when ready to use
        }
    }

    // enable the drag view for dragging
    private void startDrag(int itemIndex, int y) {
        stopDrag(itemIndex);
        Log.e ("startDrag " , "itemIndex = " + itemIndex);
        View item = getChildAt(itemIndex);                              //  ???
        Log.e ("startDrag - View item " , "item = " + item.toString());
        if (item == null) return;
        item.setDrawingCacheEnabled(true);
        if (mDragListener != null)
            mDragListener.onStartDrag(item);

        // 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
        Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());

        WindowManager.LayoutParams mWindowParams = new WindowManager.LayoutParams();
        mWindowParams.gravity = Gravity.TOP;
        mWindowParams.x = 0;
        mWindowParams.y = y - mDragPointOffset;

        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
                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
        mWindowParams.format = PixelFormat.TRANSLUCENT;
        mWindowParams.windowAnimations = 0;

        Context context = getContext();
        ImageView v = new ImageView(context);
        v.setImageBitmap(bitmap);      

        WindowManager mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        mWindowManager.addView(v, mWindowParams);
        mDragView = v;
    }

    // destroy drag view
    private void stopDrag(int itemIndex) {
        if (mDragView != null) {
            if (mDragListener != null)
                mDragListener.onStopDrag(getChildAt(itemIndex));
            mDragView.setVisibility(GONE);
            WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
            wm.removeView(mDragView);
            mDragView.setImageDrawable(null);
            mDragView = null;
        }
    }

}
4

1 に答える 1

0

この問題を解決するために、getChildAt(position)を呼び出す前にメソッドlayoutChildren()を使用しました

于 2012-11-12T10:08:30.710 に答える