Android では、ListViewドラッグ アンド ドロップを使用してアイテムを並べ替えられるようにしたいと考えています。「ドラッグ アンド ドロップ リストビュー」にはさまざまな実装があることは知っていますが、 API レベル 11以降のドラッグ アンド ドロップ フレームワークを使用したいと考えています。
ListViewドラッグアンドドロップをしながらスクロールしたくなるまで、それは非常にうまく始まりました。下の例に書いてあるように、とりあえずどのリスト要素の上にいるのかを確認するので、その位置が間ListView.getLastVisiblePosition()にない場合ListView.getFirstVisiblePosition()は a を使っListView.smoothScrollToPosition()て他のリスト項目を表示します。
初めての実装ですが、かなりうまく機能しています。
スクロール中に問題が発生します。一部の要素は、ドラッグ アンド ドロップ イベントに応答しません。他の要素はDragEvent.ACTION_DRAG_ENTERED、それらの上にいるときに応答しません。これは、ListView がアイテム ビューを管理する方法によるものです。表示されなくなったアイテム ビューをリサイクルしようとします。
問題なく動作getView()しListAdapterますが、 の が新しいオブジェクトを返す場合があります。このオブジェクトは新しいため、他のイベントDragEvent.ACTION_DRAG_STARTEDに応答しません。DragEvent
ここに例があります。この場合、リスト アイテムを長押ししてドラッグ アンド ドロップを開始し、それをドラッグすると、アイテムの上にいる場合、ほとんどのアイテムの背景が緑色になります。しかし、そうでない人もいます。
見逃した場合でも、ドラッグ アンド ドロップ イベント メカニズムにサブスクライブさせることについて何か考えはありDragEvent.ACTION_DRAG_STARTEDますか?
// Somewhere I have a ListView that use the MyViewAdapter
// MyListView _myListView = ...
// _myListView.setAdapter(new MyViewAdapter(getActivity(), ...));
_myListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
        view.startDrag(null, shadowBuilder, _myListView.getItemAtPosition(position), 0);
        return true;
    }
});
class MyViewAdapter extends ArrayAdapter<MyElement> {
    public MyViewAdapter(Context context, List<TimedElement> objects) {
        super(context, 0, objects);
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View myElementView = convertView;
        if (myElementView == null) {
            /* If the code is executed here while scrolling with a drag and drop,
             * the new view is not associated to the current drag and drop events */
            Log.d("app", "Object created!");
            // Create view
            // myElementView = ...
            // Prepare drag and drop
            myElementView.setOnDragListener(new MyElementDragListener());
        }
        // Associates view and position in ListAdapter, needed for drag and drop
        myElementView.setTag(R.id.item_position, position);
        // Continue to prepare view
        // ...
        return timedElementView;
    }
    private class MyElementDragListener implements View.OnDragListener {
        @Override
        public boolean onDrag(View v, DragEvent event) {
            final int action = event.getAction();
            switch(action) {
            case DragEvent.ACTION_DRAG_STARTED:
                return true;
            case DragEvent.ACTION_DRAG_ENTERED:
                v.setBackgroundColor(Color.GREEN);
                v.invalidate();
                return true;
            case DragEvent.ACTION_DRAG_LOCATION:
                int targetPosition = (Integer)v.getTag(R.id.item_position);
                if (event.getY() < v.getHeight()/2 ) {
                    Log.i("app", "top "+targetPosition);        
                }
                else {
                    Log.i("app", "bottom "+targetPosition);
                }
                // To scroll in ListView while doing drag and drop
                if (targetPosition > _myListView.getLastVisiblePosition()-2) {
                    _myListView.smoothScrollToPosition(targetPosition+2);
                }
                else if (targetPosition < _myListView.getFirstVisiblePosition()+2) {
                    _myListView.smoothScrollToPosition(targetPosition-2);
                }
                return true;
            case DragEvent.ACTION_DRAG_EXITED:
                v.setBackgroundColor(Color.BLUE);
                v.invalidate();
                return true;
            case DragEvent.ACTION_DROP:
            case DragEvent.ACTION_DRAG_ENDED:
            default:
               break;
            }
            return false;
        }       
    }
}