修正方法がわからないバグがあります。要点は、リストビューに 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;
}
}
}