안드로이드 목록보기 드래그 앤 드롭 정렬


132

드래그 앤 드롭 방법을 사용하여 사용자가 다시 정렬 할 수 있도록 목록보기에 레코드 목록이 있습니다. 다른 앱에서 구현 된 것을 보았지만 튜토리얼을 찾지 못했습니다. 다른 사람들도 필요로하는 것이어야합니다. 누구 든지이 작업을 수행하는 코드를 알려줄 수 있습니까?


1
정렬 가능한 목록보기를 만드는 데 도움이되는이 자습서를 찾았습니다 . 아직 테스트하지는 않았지만 비디오는 유망 해 보입니다.
Alex

@Arkde 농담, 그들은 몇 년 후에도이 질문에 대한 대답을 수락하지 않았습니다.
ArtOfWarfare 17:37에

@ArtOfWarfare 나는 불행한 일이 아스카에게 일어날 수 있다고 생각해야한다고 생각합니다. 추가 활동을 허용하지 않습니다.
heycosmo

1
@heycosmo 그것은 가능합니다 ... 그들의 SO 프로필에 따르면, miannelle은 질문을한지 불과 한 달 만에 마지막으로 방문했습니다. 또한 DSLV에 대한 훌륭한 작업 ... 더블 탭과 같은 항목으로 항목을 복제하고 드래그 할 때 항목의 그림자를 변경하도록 항목을 약간 수정했습니다 (항목마다 행 번호가 있으므로 행 번호 업데이트가 드래그 될 때 업데이트 될 수 있도록 만들었습니다.) 그들은 클래스의 다른 모든 것보다 훨씬 덜 해킹되어 GitHub에 변경 사항을 제출하지 않은 이유입니다.
ArtOfWarfare 4

github.com/bauerca/drag-sort-listview 이것을 사용하고 있으며 ListView의 ROW onLongClick을 드래그 할 수 있습니까?
Achin

답변:


85

나는 지금 얼마 동안이 일을 해왔다. 이해하기 힘들고, 내가 주장한다고 주장하지는 않지만 지금까지는 만족합니다. 내 코드와 몇 가지 데모는

코드의 기반이되는 TouchInterceptor와 매우 유사하지만 구현이 크게 변경되었습니다.

DragSortListView에는 항목을 드래그하고 섞는 동안 부드럽고 예측 가능한 스크롤이 있습니다. 항목 셔플은 드래그 / 플로팅 항목의 위치와 훨씬 더 일관됩니다. 이기종 높이 목록 항목이 지원됩니다. 드래그 스크롤은 사용자 정의가 가능합니다 (응용 프로그램이 아니라 긴 목록을 통해 빠른 드래그 스크롤을 보여줍니다). 머리글 / 바닥 글이 존중됩니다. 기타.?? 구경하다.


3
귀하의 솔루션은 매력처럼 작동합니다. 다른 사람들보다 훨씬 낫습니다. 소스 코드의 라이센스는 무엇입니까? 아파치 2.0?
다리우스 바친 스키

1
@heycosmo 데모에서 제공된 뷰를 사용하여 앱에서 레이아웃을 만들 때 몇 가지 문제가 있습니다. 여러 네임 스페이스 오류가 있습니다. 제공하는 코드를 사용하는 방법에 대한 작은 블로그 게시물을 작성해 주시겠습니까?
daniel_c05

항목을 항목 위로 드래그하는 동안 항목을 정렬하는 방식으로 코드를 수정할 가능성이 있습니까?
Alex Semeniuk

@heycosmo GitHub 리포지토리에 액세스 할 수 있습니까? 오프라인 상태 인 것 같습니다 ...
sdasdadas

8
bauerca 저장소는 더 이상 유지되지 않습니다. 이 포크는 더 활동적입니다 : github.com/JayH5/drag-sort-listview
ecdpalma

21

이제 ItemTouchHelper 로 구현하기 RecyclerView가 매우 쉽습니다 . 에서 메소드를 재정의하십시오 .onMoveItemTouchHelper.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 mush가 객체 배열 인 경우 동일한 인스턴스를 공유한다는 점에 유의하십시오. 그렇지 않으면 구현이 작동하지 않습니다. 이것은 정적 목록에는 문제가되지 않지만 로더에는 문제가 될 수 있습니다
AAverin

현재 5.0 Android 버전에서 예제를 시도했습니다. 지금 몇 가지 문제가 있습니다 ...
Torsten B

@TCA 네, 5.0에도 문제가 있습니다. 도와주세요.
Manu

6

DragListView lib는 고도 애니메이션과 같은 커스텀 애니메이션을 아주 잘 지원하여 깔끔하게 처리합니다. 또한 정기적으로 유지 관리 및 업데이트됩니다.

사용 방법은 다음과 같습니다.

1 : 먼저 gradle에 lib 추가

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. 즐겨 찾는 드래그 핸들 이미지가 포함 된 목록 항목의 레이아웃을 만들고 2 단계에서 만든 ID (예 :)에 해당 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

나는 최근에 외부 의존성이 필요없는 드래그 정렬의 작동 구현을 제공하는 이 위대한 요점 을 우연히 발견 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;
    }
});

마지막으로, 드래그 프로세스의 활성화 및 비활성화를 처리하는 stopDragstartDrag메소드의 모양은 다음과 같습니다.

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

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

이것은 가장 쉬운 구현 중 하나 인 것처럼 보이지만 나쁜 것처럼 보입니다 (행은 그냥 전환하고 실제로는 모양이 0이 아닙니다). 스크롤).
Heinzlmaen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.