将 Listview 项目拖放到另一个项目中
Drag drop Listview item into another item
我有一个包含不同项目类型的列表视图:header,文件夹和文件如下:
现在我想实现拖动文件项并将其放入文件夹项并获取源和目标 position.I不想像某些拖动排序那样在拖动时更改目标位置(重新排列)列表视图库。
有什么建议可以入手吗?
将您的 ListView
切换为 RecyclerView
将使事情变得容易得多。
您可以在 Styling Android and the whole code here.
上找到整篇文章
此代码使用 OnItemTouchListener
来检测何时应拖动项目。在 RecyclerView
上方有一个 ImageView
,其中包含正在移动的项目图像以廉价地对其进行动画处理。
OnItemTouckListener
(DragController.java
):
public class DragController implements RecyclerView.OnItemTouchListener {
private RecyclerView recyclerView;
private ImageView overlay;
private final GestureDetectorCompat gestureDetector;
private boolean isDragging = false;
public DragController(RecyclerView recyclerView, ImageView overlay) {
this.recyclerView = recyclerView;
this.overlay = overlay;
GestureDetector.SimpleOnGestureListener longClickGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
isDragging = true;
dragStart(e.getX(), e.getY());
}
};
this.gestureDetector = new GestureDetectorCompat(recyclerView.getContext(), longClickGestureListener);
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
if (isDragging) {
return true;
}
gestureDetector.onTouchEvent(e);
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
int x = (int) e.getX();
int y = (int) e.getY();
View view = recyclerView.findChildViewUnder(x, y);
if (e.getAction() == MotionEvent.ACTION_UP) {
dragEnd(view);
isDragging = false;
} else {
drag(y, view);
}
}
开始和结束拖动(DragController.java
):
private boolean isFirst = true;
private static final int ANIMATION_DURATION = 100;
private int draggingItem = -1;
private float startY = 0f;
private Rect startBounds = null;
private void dragStart(float x, float y) {
View draggingView = recyclerView.findChildViewUnder(x, y);
View first = recyclerView.getChildAt(0);
isFirst = draggingView == first;
startY = (y - draggingView.getTop());
paintViewToOverlay(draggingView);
overlay.setTranslationY(y - startY);
draggingView.setVisibility(View.INVISIBLE);
draggingItem = recyclerView.indexOfChild(draggingView);
startBounds = new Rect(draggingView.getLeft(), draggingView.getTop(), draggingView.getRight(), draggingView.getBottom());
}
private void drag(int y, View view) {
overlay.setTranslationY(y - startY);
}
private void dragEnd(View view) {
overlay.setImageBitmap(null);
view.setVisibility(View.VISIBLE);
view.setTranslationY(overlay.getTranslationY() - view.getTop());
view.animate().translationY(0f).setDuration(ANIMATION_DURATION).start();
}
private void paintViewToOverlay(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
overlay.setImageBitmap(bitmap);
overlay.setTop(0);
}
代码是Mark Allison on StylingAndroid.
写的
编辑:
But I don't know how to get the position of item when dragging is end
答案位于 part 7 样式 Android。
View view = recyclerView.findChildViewUnder(0, y);
And how can I disable drag on Folder and Header item? Just allow dragging File item?
您可以使用多个 ViewType(文件、文件夹和 header)来执行此操作。然后你可以在DragController
中使用getItemViewType只对文件开始移动。
使用RecyclerView
和ItemTouchHelper.SimpleCallback
。
您可以在 activity:
中这样设置
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list); // Your layout with RecyclerView
RecyclerView itemRecyclerView = findViewById(R.id.itemRecyclerView);
LinearLayoutManager itemLayoutManager = new LinearLayoutManager(this);
itemRecyclerView.setLayoutManager(itemLayoutManager);
itemAdapter = new ItemAdapter(); // Your adapter which extends RecyclerView.Adapter
itemRecyclerView.setAdapter(itemAdapter);
itemRecyclerView.setHasFixedSize(true);
itemDragAndDropCallback = new ItemDragAndDropCallback(this, itemRecyclerView);
// Your class which extends ItemTouchHelper.SimpleCallback
// It will be shown in the next code sample
new ItemTouchHelper(itemDragAndDropCallback)
.attachToRecyclerView(itemRecyclerView);
}
您可以使用 ItemTouchHelper.SimpleCallback
提供的项目拖动的默认功能。
以下class 将演示更改文件夹的背景颜色。项目将被放入该文件夹。
class ItemDragAndDropCallback extends ItemTouchHelper.SimpleCallback {
ItemDragAndDropCallback() {
// Choose drag and swipe directions
// Up and down is chosen for dragging
// Right and left is chosen for swiping
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
// You can reorder items here
// Do nothing in your case
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// You can react for swiping items here
// Do nothing in your case
}
// An item will be dropped into this folder
private View folder;
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
// Here you are notified that the drag operation began
if (folder != null) {
folder.setBackgroundResource(0); // Clear former folder background
}
} else if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) {
// Here you are notified that the last operation ended
if (folder != null) {
// Set folder background to a color indicating
// that an item was dropped into it
folder.setBackgroundColor(
ContextCompat.getColor(
recyclerView.getContext(), android.R.color.holo_green_dark
)
);
}
}
}
@Override
public void onChildDraw(
Canvas c,
RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
float dX,
float dY,
int actionState,
boolean isCurrentlyActive
) {
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG && isCurrentlyActive) {
// Here you are notified that the drag operation is in progress
if (folder != null) {
folder.setBackgroundResource(0); // Clear former folder background
}
float itemActualPosition = viewHolder.itemView.getTop() + dY;
// Find folder under dragged item
for (int i = 0; i < recyclerView.getChildCount(); i++) {
folder = recyclerView.getChildAt(i);
// Exclude dragged item from detection
if (!folder.equals(viewHolder.itemView)) {
// Accept folder which encloses item position
if (folder.getTop() < itemActualPosition && itemActualPosition < folder.getBottom()) {
// Set folder background to a color indicating
// that an item will be dropped into it upon release
folder.setBackgroundColor(
ContextCompat.getColor(
recyclerView.getContext(), android.R.color.holo_green_light
)
);
break;
}
}
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
当您将项目拖到文件夹上时,项目下方的文件夹背景将为浅绿色。
当您将项目放入文件夹时,其背景将为深绿色。
我有一个包含不同项目类型的列表视图:header,文件夹和文件如下:
现在我想实现拖动文件项并将其放入文件夹项并获取源和目标 position.I不想像某些拖动排序那样在拖动时更改目标位置(重新排列)列表视图库。
有什么建议可以入手吗?
将您的 ListView
切换为 RecyclerView
将使事情变得容易得多。
您可以在 Styling Android and the whole code here.
上找到整篇文章此代码使用 OnItemTouchListener
来检测何时应拖动项目。在 RecyclerView
上方有一个 ImageView
,其中包含正在移动的项目图像以廉价地对其进行动画处理。
OnItemTouckListener
(DragController.java
):
public class DragController implements RecyclerView.OnItemTouchListener {
private RecyclerView recyclerView;
private ImageView overlay;
private final GestureDetectorCompat gestureDetector;
private boolean isDragging = false;
public DragController(RecyclerView recyclerView, ImageView overlay) {
this.recyclerView = recyclerView;
this.overlay = overlay;
GestureDetector.SimpleOnGestureListener longClickGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
isDragging = true;
dragStart(e.getX(), e.getY());
}
};
this.gestureDetector = new GestureDetectorCompat(recyclerView.getContext(), longClickGestureListener);
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
if (isDragging) {
return true;
}
gestureDetector.onTouchEvent(e);
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
int x = (int) e.getX();
int y = (int) e.getY();
View view = recyclerView.findChildViewUnder(x, y);
if (e.getAction() == MotionEvent.ACTION_UP) {
dragEnd(view);
isDragging = false;
} else {
drag(y, view);
}
}
开始和结束拖动(DragController.java
):
private boolean isFirst = true;
private static final int ANIMATION_DURATION = 100;
private int draggingItem = -1;
private float startY = 0f;
private Rect startBounds = null;
private void dragStart(float x, float y) {
View draggingView = recyclerView.findChildViewUnder(x, y);
View first = recyclerView.getChildAt(0);
isFirst = draggingView == first;
startY = (y - draggingView.getTop());
paintViewToOverlay(draggingView);
overlay.setTranslationY(y - startY);
draggingView.setVisibility(View.INVISIBLE);
draggingItem = recyclerView.indexOfChild(draggingView);
startBounds = new Rect(draggingView.getLeft(), draggingView.getTop(), draggingView.getRight(), draggingView.getBottom());
}
private void drag(int y, View view) {
overlay.setTranslationY(y - startY);
}
private void dragEnd(View view) {
overlay.setImageBitmap(null);
view.setVisibility(View.VISIBLE);
view.setTranslationY(overlay.getTranslationY() - view.getTop());
view.animate().translationY(0f).setDuration(ANIMATION_DURATION).start();
}
private void paintViewToOverlay(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
overlay.setImageBitmap(bitmap);
overlay.setTop(0);
}
代码是Mark Allison on StylingAndroid.
写的编辑:
But I don't know how to get the position of item when dragging is end
答案位于 part 7 样式 Android。
View view = recyclerView.findChildViewUnder(0, y);
And how can I disable drag on Folder and Header item? Just allow dragging File item?
您可以使用多个 ViewType(文件、文件夹和 header)来执行此操作。然后你可以在DragController
中使用getItemViewType只对文件开始移动。
使用RecyclerView
和ItemTouchHelper.SimpleCallback
。
您可以在 activity:
中这样设置@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list); // Your layout with RecyclerView
RecyclerView itemRecyclerView = findViewById(R.id.itemRecyclerView);
LinearLayoutManager itemLayoutManager = new LinearLayoutManager(this);
itemRecyclerView.setLayoutManager(itemLayoutManager);
itemAdapter = new ItemAdapter(); // Your adapter which extends RecyclerView.Adapter
itemRecyclerView.setAdapter(itemAdapter);
itemRecyclerView.setHasFixedSize(true);
itemDragAndDropCallback = new ItemDragAndDropCallback(this, itemRecyclerView);
// Your class which extends ItemTouchHelper.SimpleCallback
// It will be shown in the next code sample
new ItemTouchHelper(itemDragAndDropCallback)
.attachToRecyclerView(itemRecyclerView);
}
您可以使用 ItemTouchHelper.SimpleCallback
提供的项目拖动的默认功能。
以下class 将演示更改文件夹的背景颜色。项目将被放入该文件夹。
class ItemDragAndDropCallback extends ItemTouchHelper.SimpleCallback {
ItemDragAndDropCallback() {
// Choose drag and swipe directions
// Up and down is chosen for dragging
// Right and left is chosen for swiping
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
// You can reorder items here
// Do nothing in your case
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// You can react for swiping items here
// Do nothing in your case
}
// An item will be dropped into this folder
private View folder;
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
// Here you are notified that the drag operation began
if (folder != null) {
folder.setBackgroundResource(0); // Clear former folder background
}
} else if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) {
// Here you are notified that the last operation ended
if (folder != null) {
// Set folder background to a color indicating
// that an item was dropped into it
folder.setBackgroundColor(
ContextCompat.getColor(
recyclerView.getContext(), android.R.color.holo_green_dark
)
);
}
}
}
@Override
public void onChildDraw(
Canvas c,
RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
float dX,
float dY,
int actionState,
boolean isCurrentlyActive
) {
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG && isCurrentlyActive) {
// Here you are notified that the drag operation is in progress
if (folder != null) {
folder.setBackgroundResource(0); // Clear former folder background
}
float itemActualPosition = viewHolder.itemView.getTop() + dY;
// Find folder under dragged item
for (int i = 0; i < recyclerView.getChildCount(); i++) {
folder = recyclerView.getChildAt(i);
// Exclude dragged item from detection
if (!folder.equals(viewHolder.itemView)) {
// Accept folder which encloses item position
if (folder.getTop() < itemActualPosition && itemActualPosition < folder.getBottom()) {
// Set folder background to a color indicating
// that an item will be dropped into it upon release
folder.setBackgroundColor(
ContextCompat.getColor(
recyclerView.getContext(), android.R.color.holo_green_light
)
);
break;
}
}
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
当您将项目拖到文件夹上时,项目下方的文件夹背景将为浅绿色。 当您将项目放入文件夹时,其背景将为深绿色。