ฉันมีรายการบันทึกในมุมมองรายการที่ฉันต้องการให้ผู้ใช้สามารถจัดเรียงใหม่โดยใช้วิธีการลากและวาง ฉันเคยเห็นสิ่งนี้นำไปใช้ในแอพอื่น ๆ แต่ฉันไม่พบบทช่วยสอนสำหรับมัน มันต้องเป็นสิ่งที่คนอื่นต้องการเช่นกัน ใครช่วยชี้รหัสให้ฉันทำสิ่งนี้ได้ไหม
ฉันมีรายการบันทึกในมุมมองรายการที่ฉันต้องการให้ผู้ใช้สามารถจัดเรียงใหม่โดยใช้วิธีการลากและวาง ฉันเคยเห็นสิ่งนี้นำไปใช้ในแอพอื่น ๆ แต่ฉันไม่พบบทช่วยสอนสำหรับมัน มันต้องเป็นสิ่งที่คนอื่นต้องการเช่นกัน ใครช่วยชี้รหัสให้ฉันทำสิ่งนี้ได้ไหม
คำตอบ:
ฉันทำงานนี้มาระยะหนึ่งแล้ว ยากที่จะทำให้ถูกต้องและฉันไม่ได้อ้างว่าฉันทำ แต่ฉันก็มีความสุขกับมัน รหัสของฉันและการสาธิตต่างๆสามารถพบได้ที่
การใช้งานนั้นคล้ายกับ TouchInterceptor (ซึ่งเป็นรหัสที่ใช้) แม้ว่าจะมีการเปลี่ยนแปลงการใช้งานที่สำคัญ
DragSortListView มีการเลื่อนที่ราบรื่นและคาดเดาได้ในขณะที่ลากและสับรายการ การสับเปลี่ยนรายการมีความสอดคล้องกับตำแหน่งของรายการลาก / ลอยมากขึ้น รองรับรายการที่มีความสูงต่างกัน การลากเลื่อนสามารถปรับแต่งได้ (ฉันสาธิตการลากเลื่อนอย่างรวดเร็วผ่านรายการยาว ๆ - ไม่ใช่ว่าแอปพลิเคชันอยู่ในใจ) เคารพส่วนหัว / ส่วนท้าย ฯลฯ . ?? ลองดูสิ.
ตอนนี้ก็สวยง่ายที่จะใช้สำหรับ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: ลากและปัดด้วย RecyclerView
กำลังเพิ่มคำตอบนี้เพื่อจุดประสงค์ของผู้ที่ google เกี่ยวกับเรื่องนี้ ..
เมื่อเร็ว ๆ นี้มีตอนของ DevBytes ( ListView Cell Dragging and Rearranging ) ซึ่งอธิบายถึงวิธีการทำเช่นนี้
คุณสามารถค้นหาได้ที่นี่ยังมีโค้ดตัวอย่างสามารถใช้ได้ที่นี่
สิ่งที่รหัสนี้ทำโดยทั่วไปคือสร้างdynamic listview
โดยส่วนขยายlistview
ที่รองรับการลากและสลับเซลล์ เพื่อให้คุณสามารถใช้ DynamicListView
แทนพื้นฐานของคุณListView
และนั่นคือคุณได้ติดตั้ง ListView ด้วยการลากและวาง
DragListView lib ทำสิ่งนี้ได้อย่างเรียบร้อยพร้อมการสนับสนุนที่ดีมากสำหรับภาพเคลื่อนไหวที่กำหนดเองเช่นภาพเคลื่อนไหวระดับความสูง นอกจากนี้ยังคงได้รับการดูแลและปรับปรุงอยู่เป็นประจำ
นี่คือวิธีที่คุณใช้:
1: เพิ่ม 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
ฉันพบว่าDragSortListViewทำงานได้ดีแม้ว่าการเริ่มต้นใช้งานอาจง่ายกว่า นี่คือบทแนะนำสั้น ๆ เกี่ยวกับการใช้งานใน Android Studio พร้อมรายการในหน่วยความจำ:
เพิ่มสิ่งนี้ในการbuild.gradle
อ้างอิงสำหรับแอปของคุณ:
compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
สร้างทรัพยากรสำหรับรหัสจุดจับการลากโดยสร้างหรือเพิ่มในvalues/ids.xml
:
<resources>
... possibly other resources ...
<item type="id" name="drag_handle" />
</resources>
สร้างเค้าโครงสำหรับรายการที่มีรูปภาพแฮนเดิลลากที่คุณชื่นชอบและกำหนด ID ให้กับ ID ที่คุณสร้างในขั้นตอนที่ 2 (เช่นdrag_handle
)
สร้างเค้าโครง 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"/>
ตั้งค่า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);
ตั้งค่าฟังก์ชั่นดร็อปที่จัดเรียงรายการใหม่เมื่อดรอป
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();
}
});
เมื่อเร็ว ๆ นี้ฉันได้สะดุดกับGistที่ยอดเยี่ยมนี้ซึ่งช่วยให้สามารถใช้งานการจัดเรียงแบบลากได้ListView
โดยไม่จำเป็นต้องพึ่งพาภายนอก
โดยทั่วไปจะประกอบด้วยการสร้าง Adapter ที่กำหนดเองของคุณขยายArrayAdapter
เป็นคลาสภายในไปยังกิจกรรมที่มีListView
ไฟล์. บนอะแดปเตอร์นี้จะตั้งค่าเป็นonTouchListener
รายการของคุณที่จะส่งสัญญาณการเริ่มต้นของการลาก
ใน Gist นั้นพวกเขาตั้งค่า Listener เป็นส่วนเฉพาะของเค้าโครงของ List Item ("ที่จับ" ของรายการ) ดังนั้นจึงไม่มีใครเคลื่อนย้ายโดยการกดส่วนใดส่วนหนึ่งโดยไม่ได้ตั้งใจ โดยส่วนตัวแล้วฉันชอบที่จะไปกับ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;
}
}
นอกจากนี้ยังเกี่ยวข้องกับการเพิ่ม an 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();
}