Просмотр списка Android Сортировка перетаскиванием

132

У меня есть список записей в списке, который я хочу, чтобы пользователь мог повторно отсортировать, используя метод перетаскивания. Я видел, как это реализовано в других приложениях, но я не нашел для этого учебника. Это должно быть то, что нужно и другим. Может ли кто-нибудь указать мне на какой-то код для этого?

miannelle
источник
1
Я нашел этот учебник, который может помочь в создании сортированного списка . Я еще не тестировал, но видео выглядит многообещающим
Alex
@Arkde, не шучу, они все еще не приняли ответа на этот вопрос, годы спустя.
ArtOfWarfare
@ArtOfWarfare Я думаю, следует учитывать, что с спрашивающим могло произойти что-то прискорбное ... запрет на дальнейшую деятельность.
heycosmo
1
@heycosmo Это возможно ... согласно их профилю SO, miannelle последний раз заходила через месяц после того, как задала вопрос. Кроме того, отличная работа над DSLV ... Я внес в него несколько модификаций, чтобы разрешить такие вещи, как двойное нажатие для дублирования элементов и изменение тени элемента при его перетаскивании (у каждого элемента есть свой номер строки, поэтому я сделал так, чтобы обновления номеров строк могли обновляться по мере перетаскивания.) Они вроде просто взломаны, гораздо менее элегантны, чем все остальное в классе, поэтому я не отправил изменения на GitHub.
ArtOfWarfare
github.com/bauerca/drag-sort-listview Я использую это, и можно ли перетащить ROW onLongClick из Listview?
Ачин

Ответы:

85

Я работаю над этим уже некоторое время. Трудно понять, и я не утверждаю, что верю, но пока я доволен этим. Мой код и несколько демонстраций можно найти на

Его использование очень похоже на TouchInterceptor (на котором основан код), хотя были внесены значительные изменения в реализацию.

DragSortListView имеет плавную и предсказуемую прокрутку при перетаскивании и перемещении элементов. Перестановка элементов намного больше соответствует положению перетаскиваемого / плавающего элемента. Поддерживаются элементы списков разной высоты. Прокрутка с перетаскиванием настраивается (я демонстрирую быструю прокрутку с помощью перетаскивания по длинному списку - не то что приложение приходит на ум). Верхние / нижние колонтитулы соблюдаются. и т.д.?? Взглянуть.

heycosmo
источник
3
Ваше решение работает как шарм. Намного лучше других. Какая лицензия у вашего исходного кода? Apache 2.0?
Dariusz Bacinski
1
@heycosmo У меня есть несколько проблем при создании макета в моем приложении с использованием представлений, представленных в демонстрации. Ошибка нескольких пространств имен. Не могли бы вы сделать небольшой пост в блоге о том, как использовать предоставленный вами код?
daniel_c05
Есть ли возможность изменить код таким образом, чтобы элементы сортировались не только по каплям, пока вы перетаскивали свой элемент над ними?
Alex Semeniuk
@heycosmo Можете ли вы сделать доступным свой репозиторий GitHub? Вроде офлайн ...
sdasdadas
8
Репо bauerca больше не ведется. Этот форк более активен: github.com/JayH5/drag-sort-listview
ecdpalma
21

Теперь это довольно просто реализовать RecyclerViewс помощью ItemTouchHelper . Просто переопределите 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: Drag and Swipe with RecyclerView

Birdy
источник
18

Добавляю этот ответ для тех, кто гуглит по этому поводу ..

Недавно был эпизод DevBytes ( перетаскивание и перестановка ячеек ListView ), в котором объясняется, как это сделать.

Вы можете найти его здесь, также здесь доступен образец кода .

Что в основном делает этот код, так это то, что он создает dynamic listviewрасширение, listviewкоторое поддерживает перетаскивание и замену ячеек. Так что вы можете использовать DynamicListViewвместо базового, ListView и на этом вы реализовали ListView с помощью перетаскивания.

Арун С
источник
1
При использовании реализации DevBytes имейте в виду, что ваш адаптер и DynamicListView используют один и тот же экземпляр массива if objects. Иначе реализация не сработает. Это не проблема для статических списков, но может быть проблемой для загрузчиков
AAverin
Я пробовал этот пример на текущей версии Android 5.0. Теперь у него есть проблемы ...
Торстен Б
@TCA Да, у меня тоже были проблемы с 5.0. Пожалуйста помоги.
Ману
6

Библиотека DragListView делает это действительно изящно с очень хорошей поддержкой настраиваемых анимаций, таких как анимация высоты. Он также по-прежнему поддерживается и обновляется на регулярной основе.

Вот как вы это используете:

1: сначала добавьте библиотеку в 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.

WOX
источник
5

Я обнаружил, что DragSortListView работает хорошо, хотя начать с ним было бы проще. Вот краткое руководство по его использованию в Android Studio со списком в памяти:

  1. Добавьте это в build.gradleзависимости для своего приложения:

    compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
  2. Создайте ресурс для идентификатора ручки перетаскивания, создав или добавив в values/ids.xml:

    <resources>
        ... possibly other resources ...
        <item type="id" name="drag_handle" />
    </resources>
  3. Создайте макет для элемента списка, который включает ваше любимое изображение ручки перетаскивания, и назначьте его идентификатор идентификатору, который вы создали на шаге 2 (например, 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элемент списка, который будет сигнализировать о начале перетаскивания.

В этом Gist они устанавливают слушателя на определенную часть макета элемента списка («дескриптор» элемента), поэтому его нельзя случайно переместить, нажав любую его часть. Лично я предпочел использовать 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();
}
DarkCygnus
источник
Хотя это кажется одной из самых простых реализаций, это выглядит плохо (строки просто переключаются, на самом деле нет никаких просмотров), это плохо и делает почти невозможным прокрутку списка, который не умещается на экране (я постоянно переключаю строки вместо прокрутка).
Heinzlmaen 05