[英]ItemTouchHelper: Prevent out of bounds dragging
I have a recycler view with ItemTouchHelper.我有一个带有 ItemTouchHelper 的回收器视图。 It allows dragging the items.它允许拖动项目。
I want to limit the dragging to the bounds of recycler view - ie you can't just drag the view outside the container, so that it disappears.我想将拖动限制在回收器视图的范围内 - 即您不能将视图拖到容器外,使其消失。
I tried checking the absolute coordinates like this:我试着像这样检查绝对坐标:
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
recyclerView.getLocationOnScreen(pos);
int rvY = pos[1];
viewHolder.itemView.getLocationOnScreen(pos);
int vhY = pos[1];
if (rvY > vhY || rvY + recyclerView.getHeight() < vhY + viewHolder.itemView.getHeight()) {
return;
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
...
}
but then I run into kinda rendering concurency - if I move the view slowly, it will stop moving when going out of bounds, but if I move faster - then it anyway leaves the recycler view bounds.但是后来我遇到了渲染并发性 - 如果我缓慢移动视图,它会在越界时停止移动,但是如果我移动得更快 - 那么它无论如何都会离开回收器视图边界。
Any ideas / approaches?任何想法/方法?
The dY and dX value must be clipped to the RecyclerView
's bounds: dY 和 dX 值必须剪裁到RecyclerView
的边界:
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
val clippedDx = clip(recyclerView.width, viewHolder.itemView.left, viewHolder.itemView.right, dX)
val clippedDy = clip(recyclerView.height, viewHolder.itemView.top, viewHolder.itemView.bottom, dY)
super.onChildDraw(c, recyclerView, viewHolder, clippedDx, clippedDy, actionState, isCurrentlyActive)
}
private fun clip(size: Int, start: Int, end: Int, delta: Float): Float {
val newStart = start + delta
val newEnd = end + delta
val oobStart = 0 - newStart
val oobEnd = newEnd - size
return when {
oobStart > 0 -> delta + oobStart
oobEnd > 0 -> delta - oobEnd
else -> delta
}
}
I adjusted user1185087's answer so that instead of teleporting your item, it simply won't handle it if the drag does go out.我调整了 user1185087 的答案,这样它就不会传送您的项目,如果拖动确实消失,它就不会处理它。
@Override
public void onChildDraw(@NotNull Canvas c, @NotNull RecyclerView recyclerView,
@NotNull RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
float topY = viewHolder.itemView.getTop() + dY;
float bottomY = topY + viewHolder.itemView.getHeight();
// Only redraw child if it is inbounds of view
if (topY > 0 && bottomY < recyclerView.getHeight()){
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
I have the same problem.我有同样的问题。 All answers help me find the better way without lags.所有答案都可以帮助我找到更好的方法而没有滞后。 :) :)
If use only dY it will create lags.如果仅使用dY ,则会产生滞后。 So I add position determination for itemView inside onChildDraw .所以我在onChildDraw 中为itemView添加了位置确定。
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float,
actionState: Int, isCurrentlyActive: Boolean) {
var edgeY = dY
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
val lastPosition = (recyclerView.adapter?.itemCount ?: 0) - 1
val view = viewHolder.itemView
val pieceHeight = view.height / PIECE_RATIO
val topEdge = recyclerView.top - pieceHeight
val bottomEdge = recyclerView.height - view.bottom + pieceHeight
if (movePosition == 0 && dY < topEdge) {
edgeY = topEdge
} else if (movePosition == lastPosition && dY > bottomEdge) {
edgeY = bottomEdge
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, edgeY, actionState, isCurrentlyActive)
}
Code for this:代码:
/**
* Variable need for best performance and more productive, because
* get [RecyclerView.ViewHolder.getAdapterPosition] inside [onChildDraw]
* is hard calculating operation
*/
protected var movePosition = RecyclerView.NO_POSITION
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
/**
* Get position on drag start
*/
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
movePosition = viewHolder?.adapterPosition ?: RecyclerView.NO_POSITION
}
}
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
/**
* Clear position on drag end
*/
movePosition = RecyclerView.NO_POSITION
}
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean {
/**
* Get position on drag
*/
movePosition = target.adapterPosition
return false
}
Child classes can use movePosition like this:子类可以像这样使用movePosition :
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean {
super.onMove(recyclerView, viewHolder, target)
return callback.onTouchMove(viewHolder.adapterPosition, movePosition)
}
All source code and samples you can find in link: github project您可以在链接中找到的所有源代码和示例: github 项目
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.