RecyclerView ItemTouchHelper滑动撤销

4

我将在滑动两个按钮“删除”和“取消”后显示隐藏的视图。 在我的xml itemrow中,我有两个内部Relativelayouts。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingTop="10dp">

<include
    android:id="@+id/item_container"
    layout="@layout/layout_back" />

<RelativeLayout
    android:id="@+id/front"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/quest_background_blue"
    android:orientation="horizontal"
    android:tag="front"
    android:focusableInTouchMode="true">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:layout_gravity="center_vertical"
        android:padding="8dp" />

    <include
        android:id="@+id/contprice"
        style="@style/wrap"
        layout="@layout/quest_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true" />

    <LinearLayout
        style="@style/wrap.linear"
        android:layout_gravity="center_vertical"
        android:layout_toLeftOf="@id/contprice"
        android:layout_toRightOf="@id/icon"
        android:layout_weight="0.4">

        <TextView
            android:id="@+id/title"
            style="@style/quest_title"
            android:text="Рассказать друзьям" />

        <TextView
            android:id="@+id/details"
            style="@style/quest_detail" />
    </LinearLayout>
</RelativeLayout>

</FrameLayout>

具有ID为front的RelativeLayout可滑动,在ID为item_container的包含布局中有两个按钮

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerVertical="true"
            android:background="@android:color/transparent">
<TextView
    android:id="@+id/cancel"
    android:textColor="#0eb0a0"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_alignParentRight="true"
    android:clickable="true"
    android:focusable="false"
    android:focusableInTouchMode="false"
    android:gravity="center"
    android:padding="10dp"
    android:text="Отмена"
    android:textStyle="bold"/>

<TextView
    android:id="@+id/delete"
    android:textColor="#e6007e"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_alignParentLeft="true"
    android:clickable="true"
    android:focusable="false"
    android:focusableInTouchMode="false"
    android:gravity="center"
    android:padding="10dp"
    android:text="Скрыть"
    android:textStyle="bold"/>
</RelativeLayout>

问题在于当显示带有按钮的隐藏布局时,按钮无法点击。
这里是ItemTouchHelper的实现。
public class MyItemTouchHelper extends ItemTouchHelper.SimpleCallback {

private ItemAdapter itemAdapter;
private RecyclerView recyclerView;

public MyItemTouchHelper(RecyclerView mRecyclerView, ItemAdapter itemAdapter) {
    super(0, ItemTouchHelper.START | ItemTouchHelper.END);
    this.itemAdapter = itemAdapter;
    this.recyclerView = mRecyclerView;
}

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

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
    return makeMovementFlags(0, swipeFlags);
}

@Override
public boolean isItemViewSwipeEnabled() {
    return true;
}

@Override
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
    Log.d("SWIPE", " direction = " + direction);
    final ItemAdapter.ItemViewHolder holder = (ItemAdapter.ItemViewHolder) viewHolder;
    holder.itemView.setOnClickListener(null);
    ((ItemAdapter.ItemViewHolder) viewHolder).itemContainer.bringToFront();
    ((ItemAdapter.ItemViewHolder) viewHolder).itemContainer.invalidate();
    ((ItemAdapter.ItemViewHolder) viewHolder).itemCancel.setEnabled(true);
    ((ItemAdapter.ItemViewHolder) viewHolder).itemDelete.setEnabled(true);
    ((ItemAdapter.ItemViewHolder) viewHolder).itemContainer.setVisibility(View.VISIBLE);

    ((ItemAdapter.ItemViewHolder) viewHolder).itemDelete.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(v.getContext(), "DELETE " + viewHolder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
            itemAdapter.removeItem(viewHolder.getAdapterPosition());
            recyclerView.getAdapter().notifyItemRemoved(viewHolder.getAdapterPosition());
        }
    });
    ((ItemAdapter.ItemViewHolder) viewHolder).itemCancel.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(v.getContext(), "CANCEL " + viewHolder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
            ((ItemAdapter.ItemViewHolder) viewHolder).itemContainer.setVisibility(View.INVISIBLE);
            holder.itemView.setOnClickListener(ItemAdapter.itemAdapterClickListener(viewHolder.getAdapterPosition()));
            recyclerView.getAdapter().notifyItemChanged(viewHolder.getAdapterPosition());
            clearView(recyclerView, viewHolder);
            ((ItemAdapter.ItemViewHolder) viewHolder).itemCancel.setEnabled(false);
            ((ItemAdapter.ItemViewHolder) viewHolder).itemDelete.setEnabled(false);
            ((ItemAdapter.ItemViewHolder) viewHolder).itemContext.setVisibility(View.VISIBLE);
            ((ItemAdapter.ItemViewHolder) viewHolder).itemContext.bringToFront();
            ((ItemAdapter.ItemViewHolder) viewHolder).itemContext.invalidate();
        }
    });
}


@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    if (viewHolder.getAdapterPosition() == -1) {
        return;
    }

    ItemAdapter.ItemViewHolder holder = (ItemAdapter.ItemViewHolder) viewHolder;
    if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
        if (dX > 0 || dX < 0) {
            holder.itemContext.setTranslationX(dX);

        }
    } else {
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY,
                actionState, isCurrentlyActive);
    }
}


@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    super.clearView(recyclerView, viewHolder);
    View foreground = ((ItemAdapter.ItemViewHolder) viewHolder).getSwipableView();
    getDefaultUIUtil().clearView(foreground);
}
}

在这里查看ViewHolder

 public class ItemViewHolder extends RecyclerView.ViewHolder {

    TextView itemText;
    RelativeLayout itemContainer;
    RelativeLayout itemContext;
    TextView itemDelete;
    TextView itemCancel;

    public ItemViewHolder(View itemView) {
        super(itemView);
        itemText = (TextView) itemView.findViewById(R.id.details);
        itemDelete = (TextView) itemView.findViewById(R.id.delete);
        itemCancel = (TextView) itemView.findViewById(R.id.cancel);
        itemContainer = (RelativeLayout) itemView.findViewById(R.id.item_container);
        itemContext = (RelativeLayout) itemView.findViewById(R.id.front);

    }

    public ViewGroup getSwipableView() {
        return itemContext;
    }

    public ViewGroup getItemContainer() {
        return itemContainer;
    }
}

如果说按钮点击的次数正确,但第一次尝试时无法点击
更新
在滑动后,点击项目似乎仍处于滑动模式,并且根据日志显示前三次点击是滑动方向
onSwipe
Log.d("SWIPE", " direction = " + direction);

D/SWIPE:  direction = 16
D/SWIPE:  direction = 16
D/SWIPE:  direction = 16

之后点击取消或删除按钮

2个回答

0
在你的ItemViewHolder中更改这个。
item_container = itemView.findViewById(R.id.item_container);
itemDelete = (TextView) item_container.findViewById(R.id.delete);
itemCancel = (TextView) item_container.findViewById(R.id.cancel);

并添加

View item_container;

它是可点击的,但第一次尝试仍处于滑动模式。这就像该项目仍处于滑动模式。以下是一些日志:在滑动后,前3次单击显示仍在滑动。D/SWIPE:direction = 16 D/SWIPE:direction = 16 D/SWIPE:direction = 16<pre> public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) { Log.d("SWIPE", "direction = "+direction); <code> - Trunks ssj
@Sharas 是的,大约三年前。 - Trunks ssj
那么,我猜你不记得解决方案是什么了,对吧? :-) @Trunksssj - Sharas
@Sharas 抱歉,我经常忘记在这里登录。 请检查下面的代码。 - Trunks ssj

0
class SwipeItemTouchHelper(private val adapter: QuestsAdapter) : ItemTouchHelper.Callback() {

override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder) = false

override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
    adapter.redrawViewHolder(viewHolder.adapterPosition)
}

override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
    val swipeView = viewHolder.itemView.findViewById<View>(R.id.front)
    return if (swipeView.visibility == View.INVISIBLE) 0
    else ItemTouchHelper.Callback.makeMovementFlags(0, ItemTouchHelper.START or ItemTouchHelper.END)
}

override fun onChildDraw(
        c: Canvas,
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        dX: Float,
        dY: Float,
        actionState: Int,
        isCurrentlyActive: Boolean
) {
    if (viewHolder.adapterPosition == -1) return
    if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
        viewHolder.itemView.findViewById<View>(R.id.front).apply {
            ItemTouchHelper.Callback
                    .getDefaultUIUtil()
                    .onDraw(c, recyclerView, this, dX, dY, actionState, isCurrentlyActive)
        }
    }
}

override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
    super.clearView(recyclerView, viewHolder)
    viewHolder.itemView.findViewById<View>(R.id.front).apply {
        ItemTouchHelper.Callback.getDefaultUIUtil().clearView(this)
    }
}

}

这里有一个适配器的例子,让我解释一下发生了什么。 1. 在Swipe中的itemtouch fun "onSwiped"之后,我们调用适配器fun "redrawViewHolder" 2. 在VH中,我有两个布局,前面有一些视图,后面有按钮:取消和删除 3. 在quest对象中,我们有一个标志表示滑动操作"quest.isSwiped = false",这里是true - 滑动显示backlayout,false - 显示VH的正常视图

好吧,你可以在这里查看代码,它有点旧,我放弃了它,所以需要重构 https://github.com/wlTrunks/Swipe_and_delete

class QuestsAdapter(private val quests: MutableList<Quest>) : BaseRecyclerAdapter<RecyclerBaseViewModel<*, *>>() {

fun redrawViewHolder(position: Int) {
    if (list[position].model != null) (list[position].model as BackQuest).isSwiped = true
    (quests[position] as? BackQuest)?.let {
        it.isSwiped = true
        notifyItemChanged(position)
    }
}

fun onCancelClick(questId: String) {
    currentQuest(quests, questId) { index, quest ->
        if (list[index].model != null) (list[index].model as BackQuest).isSwiped = false
        quest.isSwiped = false
        notifyItemChanged(index)
    }
}

fun onDeleteClick(questId: String) {
    currentQuest(quests, questId) { index, _ ->
        list.removeAt(index)
        quests.removeAt(index)
        notifyItemRemoved(index)
    }
}

}


现在看来,经过3年的时间,可以用更优雅的方式完成这个任务。 - Trunks ssj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接