Danh sách Android Xem loại kéo và thả


132

Tôi có một danh sách các bản ghi trong một listview mà tôi muốn người dùng có thể sắp xếp lại bằng phương pháp kéo và thả. Tôi đã thấy điều này được thực hiện trong các ứng dụng khác, nhưng tôi chưa tìm thấy hướng dẫn cho nó. Nó phải là thứ mà người khác cũng cần. Bất cứ ai có thể chỉ cho tôi một số mã để làm điều này?


1
Tôi đã tìm thấy hướng dẫn này có thể giúp tạo một chế độ xem danh sách có thể sắp xếp . Tôi chưa thử nó nhưng video có vẻ đầy hứa hẹn
Alex

@Arkde không đùa, họ vẫn chưa chấp nhận câu trả lời cho câu hỏi này, nhiều năm sau.
ArtOfWarfare

@ArtOfWarfare Tôi đoán người ta nên xem xét rằng điều gì đó không may có thể xảy ra với người hỏi ... không cho phép hoạt động thêm.
heycosmo

1
@heycosmo Có thể ... theo hồ sơ SO của họ, miannelle đã truy cập lần cuối chỉ một tháng sau khi đặt câu hỏi. Ngoài ra, công việc tuyệt vời trên DSLV ... Tôi đã thực hiện một vài sửa đổi cho nó để cho phép những thứ như chạm hai lần vào các mục trùng lặp và thay đổi bóng của vật phẩm khi nó được kéo xung quanh (mỗi mục của tôi đều có số hàng của chúng trên đó, vì vậy tôi làm cho nó để các bản cập nhật số hàng có thể cập nhật khi nó được kéo.) Chúng vừa mới bị hack, kém thanh lịch hơn mọi thứ khác trong lớp, vì vậy tại sao tôi không gửi các thay đổi cho GitHub.
ArtOfWarfare

github.com/bauerca/drag-sort-listview tôi đang sử dụng cái này và có thể kéo ROW trênLongClick của Listview không?
Achin

Câu trả lời:


85

Tôi đã làm việc về điều này một thời gian. Khó khăn để có được đúng, và tôi không yêu cầu tôi làm, nhưng tôi hài lòng với nó cho đến nay. Mã của tôi và một số bản demo có thể được tìm thấy tại

Việc sử dụng của nó rất giống với TouchInterceptor (dựa trên mã), mặc dù những thay đổi triển khai quan trọng đã được thực hiện.

DragSortListView có khả năng cuộn mượt mà và có thể dự đoán được trong khi kéo và xáo trộn các mục. Xáo trộn vật phẩm phù hợp hơn nhiều với vị trí của vật phẩm kéo / nổi. Các mục danh sách chiều cao không đồng nhất được hỗ trợ. Cuộn kéo có thể tùy chỉnh (Tôi chứng minh kéo nhanh cuộn qua một danh sách dài --- không phải là một ứng dụng xuất hiện trong tâm trí). Tiêu đề / chân trang được tôn trọng. Vân vân.?? Hãy xem.


3
Giải pháp của bạn hoạt động như một lá bùa. Tốt hơn nhiều so với những người khác. Giấy phép mã nguồn của bạn là gì? Apache 2.0?
Dariusz Bacinski

1
@heycosmo Tôi có một vài vấn đề khi tạo bố cục trong ứng dụng của mình bằng cách sử dụng các chế độ xem được cung cấp trên bản demo. Một số lỗi không gian tên, bạn có thể vui lòng làm một blogpost nhỏ về cách sử dụng mã bạn cung cấp không?
daniel_c05

Có khả năng sửa đổi mã theo cách các mục được sắp xếp không chỉ trong khi bạn kéo vật phẩm của mình lên trên chúng không?
Alex Semeniuk

@heycosmo Bạn có thể truy cập kho GitHub của mình không? Có vẻ như ngoại tuyến ...
sdasdadas

8
Repo bauerca không còn được duy trì. Ngã ba này hoạt động nhiều hơn: github.com/JayH5/drag-sort-listview
ecdpalma 30/03/2015

21

Bây giờ thật dễ dàng để thực hiện RecyclerViewvới ItemTouchHelper . Chỉ cần ghi đè onMovephương thức từ ItemTouchHelper.Callback:

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

Hướng dẫn khá hay về điều này có thể được tìm thấy tại Medium.com: Kéo và vuốt với RecyclerView


18

Đang thêm câu trả lời này cho mục đích của những người google về điều này ..

Gần đây có một tập DevBytes ( Kéo và sắp xếp lại ô ListView ) giải thích cách thực hiện việc này

Bạn có thể tìm thấy nó ở đây cũng là mã mẫu có sẵn ở đây .

Những gì mã này về cơ bản là nó tạo ra dynamic listviewbởi phần mở rộng của listviewhỗ trợ kéo và hoán đổi ô. Vì vậy, bạn có thể sử dụng DynamicListViewthay vì cơ bản ListView và đó là bạn đã triển khai ListView với Kéo và Thả.


1
Khi sử dụng triển khai DevBytes, hãy nhớ rằng bộ điều hợp và DynamicListView của bạn chia sẻ cùng một thể hiện nếu mảng đối tượng. Nếu không thực hiện sẽ không hoạt động. Đây không phải là vấn đề đối với danh sách tĩnh nhưng có thể là một thách thức với
Trình tải

Tôi đã thử ví dụ trên phiên bản Android 5.0 hiện tại. Hiện tại nó có một số vấn đề ...
Torsten B

@TCA Vâng, tôi cũng gặp vấn đề trên 5.0. Xin vui lòng giúp đỡ.
Manu

6

DragListView lib thực hiện điều này thực sự gọn gàng với sự hỗ trợ rất tốt cho các hình động tùy chỉnh như hình động độ cao. Nó cũng vẫn được duy trì và cập nhật một cách thường xuyên.

Đây là cách bạn sử dụng nó:

1: Thêm lib để phân loại đầu tiên

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

2: Thêm danh sách từ xml

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

3: Đặt trình nghe kéo

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

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

4: Tạo bộ điều hợp ghi đè từ DragItemAd CHƯƠNG

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: Triển khai một khung nhìn mở rộng từ DragItemAd Module.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;
    }
}

Để biết thêm thông tin chi tiết, hãy truy cập https://github.com/woxblom/DragListView


5

Tôi thấy DragSortListView hoạt động tốt, mặc dù bắt đầu với nó có thể dễ dàng hơn. Đây là một hướng dẫn ngắn gọn về việc sử dụng nó trong Android Studio với danh sách trong bộ nhớ:

  1. Thêm phần này vào phần build.gradlephụ thuộc cho ứng dụng của bạn:

    compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
  2. Tạo tài nguyên cho ID xử lý kéo bằng cách tạo hoặc thêm vào values/ids.xml:

    <resources>
        ... possibly other resources ...
        <item type="id" name="drag_handle" />
    </resources>
  3. Tạo bố cục cho một mục danh sách bao gồm hình ảnh xử lý kéo yêu thích của bạn và gán ID của nó cho ID bạn đã tạo ở bước 2 (ví dụ drag_handle).

  4. Tạo bố cục DragSortListView, đại loại như thế này:

    <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. Đặt ArrayAdapterđạo hàm với getViewghi đè hiển thị chế độ xem mục danh sách của bạn.

        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. Đặt một trình lắng nghe thả sắp xếp lại các mục khi chúng bị rơi.

        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

Gần đây tôi đã tình cờ thấy Gist tuyệt vời này cung cấp một triển khai hoạt động của một loại kéo ListView, không cần phụ thuộc bên ngoài.


Về cơ bản, nó bao gồm việc tạo Bộ điều hợp tùy chỉnh của bạn mở rộng ArrayAdapternhư một lớp bên trong cho hoạt động chứa của bạn ListView. Trên bộ điều hợp này, sau đó đặt một onTouchListenermục Danh sách của bạn sẽ báo hiệu bắt đầu kéo.

Trong Gist đó, họ đặt cho người nghe một phần cụ thể trong bố cục của Mục Danh sách ("tay cầm" của mục), do đó người ta không vô tình di chuyển nó bằng cách nhấn bất kỳ phần nào của nó. Cá nhân, tôi thích đi với một onLongClickListenerthay thế, nhưng đó là tùy thuộc vào bạn để quyết định. Đây là một đoạn trích của phần đó:

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;
    }
}

Điều này cũng bao gồm việc thêm một onTouchListenerđến ListView, mà kiểm tra nếu một mục đang được kéo, tay cầm những trao đổi và huỷ bỏ hiệu lực, và dừng lại tình trạng kéo. Một đoạn trích của phần đó:

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;
    }
});

Cuối cùng, đây là cách stopDragstartDragcác phương thức trông như thế nào, xử lý việc kích hoạt và vô hiệu hóa quá trình kéo:

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

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

Mặc dù đây có vẻ là một trong những cách triển khai dễ nhất, nhưng nó có vẻ tệ (các hàng chỉ chuyển đổi, thực sự trông không có gì), nó cảm thấy tồi tệ và khiến việc cuộn qua một danh sách không phù hợp với màn hình gần như không thể (tôi liên tục chuyển hàng thay vì cuộn).
Heinzlmaen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.