Androidリストビューのドラッグアンドドロップソート


132

リストビューにレコードのリストがあり、ユーザーがドラッグアンドドロップメソッドを使用して再ソートできるようにしたい。これは他のアプリに実装されているのを見てきましたが、チュートリアルは見つかりませんでした。それは他の人にも必要なものでなければなりません。これを行うためのコードを誰かに教えてもらえますか?


1
ソート可能なリストビュー作成するのに役立つこのチュートリアルを見つけました。私はまだテストしていませんが、ビデオは有望に見えます
Alex

@Arkde冗談ではありません。彼らは、この質問に対する回答をまだ何年も受け入れていません。
ArtOfWarfare

@ArtOfWarfare質問者に不運なことが起こったかもしれないと考えるべきだと思います...それ以上の活動を禁止します。
heycosmo

1
@heycosmoそれは可能です...彼らのSOプロファイルによると、ミアンネルは質問をしてからわずか1か月前に最後に訪問しました。また、DSLVについてもすばらしい作業を行いました。ダブルタップなどでアイテムを複製したり、ドラッグされているアイテムの影を変更したりできるように、いくつかの変更を加えました(アイテムにはそれぞれ行番号が付いているため、行番号の更新は、ドラッグされると更新できるようにしました。)これらはハッキングされただけで、クラスの他のすべてのものよりもはるかにエレガントではないため、GitHubに変更を送信していません。
ArtOfWarfare

github.com/bauerca/drag-sort-listview私はこれを使用していますが、リストビューのROW onLongClickをドラッグすることは可能ですか?
Achin、2015

回答:


85

私はこれにしばらく取り組んできました。正しく理解するのは難しいですが、そうは言えませんが、今のところ満足しています。私のコードといくつかのデモは、

その使用法はTouchInterceptor(コードのベース)とよく似ていますが、実装に大幅な変更が加えられています。

DragSortListViewは、アイテムのドラッグおよびシャッフル中に、スムーズで予測可能なスクロールを行います。アイテムのシャッフルは、ドラッグ/フローティングアイテムの位置とはるかに一貫しています。高さの異なるリスト項目がサポートされています。ドラッグスクロールはカスタマイズ可能です(私は長いリストをすばやくドラッグスクロールすることを示しています---アプリケーションが思い浮かぶわけではありません)。ヘッダー/フッターが尊重されます。等。??見てください。


3
あなたのソリューションは魅力のように機能します。他のものよりもはるかに優れています。ソースコードのライセンスは何ですか?Apache 2.0?
Dariusz Bacinski

1
@heycosmoデモで提供されるビューを使用してアプリでレイアウトを作成するときにいくつかの問題があります。いくつかの名前空間エラー、提供したコードの使用方法について簡単なブログ投稿をお願いしますか?
daniel_c05 2013

アイテムをドロップするときだけでなく、アイテムをアイテムの上にドラッグしているときにコードが変更される可能性はありますか?
Alex Semeniuk 2013年

@heycosmo GitHubリポジトリにアクセスできるようにできますか?オフラインのようです...
sdasdadas

8
バウエルカレポはもはや維持されません。このフォークはよりアクティブです:github.com/JayH5/drag-sort-listview
ecdpalma

21

これでRecyclerViewItemTouchHelperを使用して簡単に実装できます。onMoveからのメソッドをオーバーライドするだけItemTouchHelper.Callbackです:

 @Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    mMovieAdapter.swap(viewHolder.getAdapterPosition(), target.getAdapterPosition());
    return true;
}

これに関するかなり良いチュートリアルは、medium.comにあります。RecyclerViewでドラッグアンドスワイプします。


18

これについてグーグルする人のためにこの答えを追加しています。

最近、これを行う方法を説明するDevBytes(ListViewセルのドラッグと並べ替え)の エピソードがありました

あなたはそれをここで見つけることができ、サンプルコードもここで利用可能です

このコードが基本的に行うことは、セルのドラッグとスワッピングをサポートdynamic listviewするの拡張によってを作成することlistviewです。DynamicListView基本の代わりにを使用できるようにするため に、ListView ドラッグアンドドロップでListViewを実装しました。


1
DevBytes実装を使用するときは、オブジェクト配列の場合、アダプターとDynamicListViewが同じインスタンスを共有することに注意してください。そうでない場合、実装は機能しません。これは静的リストの問題ではありませんが、ローダーでは問題になる可能性があります
AAverin 2014年

現在の5.0 Androidバージョンで例を試しました。今、いくつかの問題があります...
Torsten B

@TCAええ、私も5.0で問題を抱えていました。助けてください。
Manu

6

DragListView libは、高度なアニメーションなどのカスタムアニメーションの非常に優れたサポートにより、これを本当に適切に実行します。また、定期的に維持および更新されます。

使い方は次のとおりです。

1:まずlibをgradleに追加します

dependencies {
    compile 'com.github.woxthebox:draglistview:1.2.1'
}

2:XMLからリストを追加する

<com.woxthebox.draglistview.DragListView
    android:id="@+id/draglistview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

3:ドラッグリスナーを設定する

mDragListView.setDragListListener(new DragListView.DragListListener() {
    @Override
    public void onItemDragStarted(int position) {
    }

    @Override
    public void onItemDragEnded(int fromPosition, int toPosition) {
    }
});

4:DragItemAdapterからオーバーライドされたアダプターを作成する

public class ItemAdapter extends DragItemAdapter<Pair<Long, String>, ItemAdapter.ViewHolder>
    public ItemAdapter(ArrayList<Pair<Long, String>> list, int layoutId, int grabHandleId, boolean dragOnLongPress) {
        super(dragOnLongPress);
        mLayoutId = layoutId;
        mGrabHandleId = grabHandleId;
        setHasStableIds(true);
        setItemList(list);
}

5:DragItemAdapter.ViewHolderから拡張するビューホルダーを実装する

public class ViewHolder extends DragItemAdapter.ViewHolder {
    public TextView mText;

    public ViewHolder(final View itemView) {
        super(itemView, mGrabHandleId);
        mText = (TextView) itemView.findViewById(R.id.text);
    }

    @Override
    public void onItemClicked(View view) {
    }

    @Override
    public boolean onItemLongClicked(View view) {
        return true;
    }
}

詳細については、https://github.com/woxblom/DragListViewにアクセスしてください


5

私が見つかりました。DragSortListViewは、それが簡単にされている可能性がで始めるが、うまくいきました。以下は、インメモリリストを使用したAndroid Studioでの使用に関する簡単なチュートリアルです。

  1. これをbuild.gradleアプリの依存関係に追加します。

    compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
  2. に作成または追加して、ドラッグハンドルIDのリソースを作成しますvalues/ids.xml

    <resources>
        ... possibly other resources ...
        <item type="id" name="drag_handle" />
    </resources>
  3. お気に入りのドラッグハンドルイメージを含むリストアイテムのレイアウトを作成し、そのIDをステップ2で作成したIDに割り当てます(例:)drag_handle

  4. 次のようなDragSortListViewレイアウトを作成します。

    <com.mobeta.android.dslv.DragSortListView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:dslv="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        dslv:drag_handle_id="@id/drag_handle"
        dslv:float_background_color="@android:color/background_light"/>
  5. リストアイテムビューをレンダリングArrayAdapterするgetViewオーバーライドで派生物を設定します。

        final ArrayAdapter<MyItem> itemAdapter = new ArrayAdapter<MyItem>(this, R.layout.my_item, R.id.my_item_name, items) { // The third parameter works around ugly Android legacy. http://stackoverflow.com/a/18529511/145173
            @Override public View getView(int position, View convertView, ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                MyItem item = getItem(position);
                ((TextView) view.findViewById(R.id.my_item_name)).setText(item.getName());
                // ... Fill in other views ...
                return view;
            }
        };
    
        dragSortListView.setAdapter(itemAdapter);
  6. ドロップされるときに項目を再配置するドロップリスナーを設定します。

        dragSortListView.setDropListener(new DragSortListView.DropListener() {
            @Override public void drop(int from, int to) {
                MyItem movedItem = items.get(from);
                items.remove(from);
                if (from > to) --from;
                items.add(to, movedItem);
                itemAdapter.notifyDataSetChanged();
            }
        });

3

私は最近、外部ソートを必要とせずに、ドラッグソートの実用的な実装を提供するこの素晴らしいGistに出会いましListView


基本的には、をArrayAdapter含むアクティビティの内部クラスとして拡張するカスタムアダプタの作成で構成されますListView。このアダプタonTouchListenerでは、ドラッグの開始を知らせるリストアイテムにを設定します。

その要点では、リスナーをリストアイテムのレイアウトの特定の部分(アイテムの「ハンドル」)に設定しているため、誤ってリストの一部を押して移動することはありません。個人的に、私はonLongClickListener代わりに行くことを好みましたが、それはあなた次第です。ここでその部分の抜粋:

public class MyArrayAdapter extends ArrayAdapter<String> {

    private ArrayList<String> mStrings = new ArrayList<String>();
    private LayoutInflater mInflater;
    private int mLayout;

    //constructor, clear, remove, add, insert...

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        View view = convertView;
        //inflate, etc...

        final String string = mStrings.get(position);
        holder.title.setText(string);

        // Here the listener is set specifically to the handle of the layout
        holder.handle.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                    startDrag(string);
                    return true;
                }
                return false;
            }
        });

        // change color on dragging item and other things...         

        return view;
    }
}

これにはへのの追加も含まonTouchListenerれますListView。これは、アイテムがドラッグされているかどうかを確認し、スワッピングと無効化を処理し、ドラッグ状態を停止します。その部分の抜粋:

mListView.setOnTouchListener(new View.OnTouchListener() {
     @Override
     public boolean onTouch(View view, MotionEvent event) {
        if (!mSortable) { return false; }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                // get positions
                int position = mListView.pointToPosition((int) event.getX(), 
                    (int) event.getY());
                if (position < 0) {
                    break;
                }
                // check if it's time to swap
                if (position != mPosition) {
                    mPosition = position;
                    mAdapter.remove(mDragString);
                    mAdapter.insert(mDragString, mPosition);
                }
                return true;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_OUTSIDE: {
                //stop drag state
                stopDrag();
                return true;
            }
        }
        return false;
    }
});

最後に、ドラッグプロセスの有効化と無効化を処理するstopDragおよびstartDragメソッドの外観を次に示します。

public void startDrag(String string) {
    mPosition = -1;
    mSortable = true;
    mDragString = string;
    mAdapter.notifyDataSetChanged();
}

public void stopDrag() {
    mPosition = -1;
    mSortable = false;
    mDragString = null;
    mAdapter.notifyDataSetChanged();
}

これは最も簡単な実装の1つであるように見えますが、見た目が悪く(行が切り替わるだけで、実際には見た目はゼロです)、見た目が悪く、画面に収まらないリストをスクロールすることが不可能に近くなります(常に行を切り替えるのではなく、スクロール)。
Heinzlmaen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.