gpt4 book ai didi

java - RecyclerView 的项目在屏幕上的位置在运行时发生变化

转载 作者:行者123 更新时间:2023-12-03 20:48:53 27 4
gpt4 key购买 nike

我有这个RecyclerView任何一个item都可以点击打开,打开的时候会变大(图1是关闭的item,图2是打开的item)
项目的布局文件包含两种状态 - 关闭卡片和打开卡片。要在它们之间切换,我只更改任何状态的可见性。以下是控制项目打开(扩展)或关闭(收缩)的方法:

    /**
* handles the expanding functionality.
*/
public void expand() {
shrink = true;
if (expandedItem != -1) {
notifyItemChanged(expandedItem);
}
expandedItem = getLayoutPosition();

toggleExpandShrinkIcon(true);
if (!openedFromParent[1]) {
openedFromParent[1] = true;
} else {
openedFromParent[0] = false;
}
expandedContainer.setVisibility(View.VISIBLE);
shrunkProgressBar.setVisibility(View.INVISIBLE);
}

/**
* handles the shrinking functionality.
*/
public void shrink() {
toggleExpandShrinkIcon(false);
expandedContainer.setVisibility(View.GONE);
shrunkProgressBar.setVisibility(View.VISIBLE);
shrink = false;
}
这些方法位于 RecyclerView的适配器,位于 ViewHolder 内部的类,它们是公开的,所以我也可以在 RecyclerView 中使用它们的适配器类(不仅通过单击),就像我在一个项目悬停在另一个项目时所做的那样。
最近我添加了拖动悬停功能(使用 this library ),以便我可以将任何项目拖动到任何其他项目的顶部,当一个项目悬停在另一个项目上时,较低的项目被打开。
当一个项目被打开时,它会插入它下面的所有其他项目,以便能够在不隐藏它下面的项目的情况下展开(就像在第一个视频中一样)。
当从悬停一个项目移动到另一个项目时,比如从第二个项目到第三个项目,当悬停第二个项目时,它被打开并且第三个项目被向下推,当移动到第三个项目时,第二个项目被关闭,但是第三个项目项目不会备份。
然后当悬停第三个项目时,它会在第四个项目上打开(请参阅第二个视频以更好地理解)。
这是处理悬停 Action 的类中的代码:
public class HoveringCallback extends ItemTouchHelper.SimpleCallback {
//re-used list for selecting a swap target
private List<RecyclerView.ViewHolder> swapTargets = new ArrayList<>();
//re used for for sorting swap targets
private List<Integer> distances = new ArrayList<>();
private float selectedStartX;
private float selectedStartY;

public interface OnDroppedListener {
void onDroppedOn(ActiveGoalsAdapter.ActiveGoalsViewHolder viewHolder, ActiveGoalsAdapter.ActiveGoalsViewHolder target);
}

private List<OnDroppedListener> onDroppedListeners = new ArrayList<>();
@Nullable
private RecyclerView recyclerView;
@Nullable
ActiveGoalsAdapter.ActiveGoalsViewHolder selected;
@Nullable
private ActiveGoalsAdapter.ActiveGoalsViewHolder hovered;

ItemBackgroundCallback backgroundCallback;

public HoveringCallback() {
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
}

public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
this.recyclerView = recyclerView;
}

public void addOnDropListener(OnDroppedListener listener) {
onDroppedListeners.add(listener);
}

public void removeOnDropListener(OnDroppedListener listener) {
onDroppedListeners.remove(listener);
}

@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (viewHolder == null) {
if (hovered != null) {
notifyDroppedOnListeners(hovered);
}
} else {
selectedStartX = viewHolder.itemView.getLeft();
selectedStartY = viewHolder.itemView.getTop();
}
this.selected = (ActiveGoalsAdapter.ActiveGoalsViewHolder) viewHolder;
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE && viewHolder != null) {
viewHolder.itemView.setBackgroundColor(backgroundCallback.getDraggingBackgroundColor(viewHolder));
}
}

private void notifyDroppedOnListeners(ActiveGoalsAdapter.ActiveGoalsViewHolder holder) {
for (OnDroppedListener listener : onDroppedListeners) {
listener.onDroppedOn(selected, (ActiveGoalsAdapter.ActiveGoalsViewHolder) holder);
}
}

@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setBackgroundColor(backgroundCallback.getDefaultBackgroundColor(viewHolder));
}

@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}

@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}

@Override
public void onChildDraw(Canvas canvas, RecyclerView parent, RecyclerView.ViewHolder viewHolder,
float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(canvas, parent, viewHolder, dX, dY, actionState, isCurrentlyActive);

if (actionState != ItemTouchHelper.ACTION_STATE_DRAG) {
return;
}

if (recyclerView == null || selected == null) {
return;
}

final RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
final int childCount = lm.getChildCount();
List<RecyclerView.ViewHolder> swapTargets = findSwapTargets((ActiveGoalsAdapter.ActiveGoalsViewHolder) viewHolder, dX, dY);
final int x = (int) (selectedStartX + dX);
final int y = (int) (selectedStartY + dY);

hovered = (ActiveGoalsAdapter.ActiveGoalsViewHolder) chooseDropTarget((ActiveGoalsAdapter.ActiveGoalsViewHolder) viewHolder, swapTargets, x, y);
if (hovered == null) {
this.swapTargets.clear();
this.distances.clear();
}
for (int i = 0; i < childCount; i++) {
final View child = lm.getChildAt(i);

if (viewHolder.itemView == child) {
continue;
}

ActiveGoalsAdapter.ActiveGoalsViewHolder childViewHolder = (ActiveGoalsAdapter.ActiveGoalsViewHolder) parent.findContainingViewHolder(child);

if (childViewHolder == null || childViewHolder.getAdapterPosition() == RecyclerView.NO_POSITION) {
continue;
}

final int count = canvas.save();
if (childViewHolder == hovered) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
childViewHolder.expand();
}
}, 500);
} else {
if(!childViewHolder.isShrunk()) {
childViewHolder.shrink();
if(canvas.getSaveCount() != count) {
canvas.restoreToCount(count);
}
}
}
}
}

private List<RecyclerView.ViewHolder> findSwapTargets(ActiveGoalsAdapter.ActiveGoalsViewHolder viewHolder, float dX, float dY) {
swapTargets.clear();
distances.clear();
final int margin = getBoundingBoxMargin();
final int left = Math.round(selectedStartX + dX) - margin;
final int top = Math.round(selectedStartY + dY) - margin;
final int right = left + viewHolder.itemView.getWidth() + 2 * margin;
final int bottom = top + viewHolder.itemView.getHeight() + 2 * margin;
final int centerX = (left + right) / 2;
final int centerY = (top + bottom) / 2;
final RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
final int childCount = lm.getChildCount();
for (int i = 0; i < childCount; i++) {
View other = lm.getChildAt(i);
if (other == viewHolder.itemView) {
continue; //myself!
}
if (other.getBottom() < top || other.getTop() > bottom
|| other.getRight() < left || other.getLeft() > right) {
continue;
}
final ActiveGoalsAdapter.ActiveGoalsViewHolder otherVh = (ActiveGoalsAdapter.ActiveGoalsViewHolder) recyclerView.getChildViewHolder(other);
if (canDropOver(recyclerView, selected, otherVh)) {
// find the index to add
final int dx = Math.abs(centerX - (other.getLeft() + other.getRight()) / 2);
final int dy = Math.abs(centerY - (other.getTop() + other.getBottom()) / 2);
final int dist = dx * dx + dy * dy;

int pos = 0;
final int cnt = swapTargets.size();
for (int j = 0; j < cnt; j++) {
if (dist > distances.get(j)) {
pos++;
} else {
break;
}
}
swapTargets.add(pos, otherVh);
distances.add(pos, dist);
}
}
return swapTargets;
}

@Override
public float getMoveThreshold(RecyclerView.ViewHolder viewHolder) {
return 0.05f;
}

@Override
public RecyclerView.ViewHolder chooseDropTarget(RecyclerView.ViewHolder selected,
List<RecyclerView.ViewHolder> dropTargets,
int curX, int curY) {
int right = curX + selected.itemView.getWidth();
int bottom = curY + selected.itemView.getHeight();
ActiveGoalsAdapter.ActiveGoalsViewHolder winner = null;
int winnerScore = -1;
final int dx = curX - selected.itemView.getLeft();
final int dy = curY - selected.itemView.getTop();
final int targetsSize = dropTargets.size();
for (int i = 0; i < targetsSize; i++) {
final ActiveGoalsAdapter.ActiveGoalsViewHolder target = (ActiveGoalsAdapter.ActiveGoalsViewHolder) dropTargets.get(i);
if (dx > 0) {
int diff = target.itemView.getRight() - right;
if (diff < 0 && target.itemView.getRight() > selected.itemView.getRight()) {
final int score = Math.abs(diff);
if (score > winnerScore) {
winnerScore = score;
winner = target;
}
}
}
if (dx < 0) {
int diff = target.itemView.getLeft() - curX;
if (diff > 0 && target.itemView.getLeft() < selected.itemView.getLeft()) {
final int score = Math.abs(diff);
if (score > winnerScore) {
winnerScore = score;
winner = target;
}
}
}
if (dy < 0) {
int diff = target.itemView.getTop() - curY;
if (target.itemView.getTop() < selected.itemView.getTop()) {
final int score = Math.abs(diff);
if (score > winnerScore) {
winnerScore = score;
winner = target;
}
}
}

if (dy > 0) {
int diff = target.itemView.getBottom() - bottom;
if (target.itemView.getBottom() > selected.itemView.getBottom()) {
final int score = Math.abs(diff);
if (score > winnerScore) {
winnerScore = score;
winner = target;
}
}
}
}
return winner;
}
}
我该如何解决这个问题? (让第三个项目回上,就像释放拖动时一样,在第二个视频的末尾)
帮助将不胜感激! (:
第一张图片(关闭项目):
closed item
第二张图片(打开的项目):
opened item
第一个视频(项目在列表中打开和关闭):
item gets opened & closed in the list
第二个视频(拖动的项目):
item dragged with the bug

最佳答案

在没有研究图书馆代码的情况下,我假设位置正在改变,所以很可能 .notifyItemChanged(位置) 被调用,并在其中展开函数调用,因为没有检查来隔离 展开功能来自未处理的事件
一个简单的答案可以是保存状态并禁用项目的扩展
长按项目时将 isDragActive 设置为 true

private static isDragActive = false
@Overrides
public onCreateViewHolder(){
itemView.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int pos, long id) {
isDragActive = true;
return true;
}
});
}

public void expand() {
if(!isDragActive){
shrink = true;
if (expandedItem != -1) {
notifyItemChanged(expandedItem);
}
expandedItem = getLayoutPosition();

toggleExpandShrinkIcon(true);
if (!openedFromParent[1]) {
openedFromParent[1] = true;
} else {
openedFromParent[0] = false;
}
expandedContainer.setVisibility(View.VISIBLE);
shrunkProgressBar.setVisibility(View.INVISIBLE);
}
}
您也可以使用下面给出的库而不是上面的解决方案
https://github.com/mikepenz/FastAdapter

关于java - RecyclerView 的项目在屏幕上的位置在运行时发生变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64078086/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com