📜  颤动列表视图蓝色动画删除 (1)

📅  最后修改于: 2023-12-03 15:42:28.670000             🧑  作者: Mango

颤动列表视图蓝色动画删除

要实现在列表视图中添加删除选项光标颤动、背景变蓝、出现动画的效果,可以按照以下步骤进行:

  1. 添加动画资源

在项目的 drawable 文件夹中,新建一个 xml 文件,用于定义删除选项的动画效果。比如可以命名为 delete_animation.xml。在该文件中,可以使用 Android 提供的属性指定动画的目标属性,例如 alpha 表示透明度、scale 表示缩放等等。

示例代码:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale android:fromXScale="1.0"
           android:toXScale="0.0"
           android:fromYScale="1.0"
           android:toYScale="0.0"
           android:pivotX="50%"
           android:pivotY="50%"
           android:duration="300"/>
    <alpha android:fromAlpha="1.0"
           android:toAlpha="0.0"
           android:duration="300"/>
</set>

上述代码中,set 标签代表动画集合,其中包含两个子标签 scale 和 alpha。它们的作用分别是缩放和渐隐,可通过属性指定缩放比例、透明度和执行时间等参数。

  1. 定义列表项布局

在列表项布局文件中,添加一个删除控件,例如一个 ImageButton。这个控件可以使用一张删除的图片作为背景。在删除控件中,定义点击事件的监听器,以响应用户的删除操作。

在这个列表项布局文件中,还需要维护一个布尔型变量 isEditMode,用于记录当前是否处在删除模式。控件的 TextView 等 View 还需要跟这个变量绑定,并且根据 isEditMode 呈现不同的效果。例如在“非删除模式”下,标题文本居左,删除控件隐藏起来。而在“删除模式”下,标题文本向右偏移,同时删除控件出现在右侧。

示例代码:

<RelativeLayout...>
    <TextView...
        android:id="@+id/item_title"
        android:textSize="14sp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="70dp"
        android:gravity="center_vertical"
        android:textColor="@color/black"
        android:ellipsize="end"
        android:maxLines="1"
        android:focusable="false"
        android:focusableInTouchMode="false"/>
    <ImageView...
        android:id="@+id/item_delete"
        android:layout_width="50dp"
        android:layout_height="30dp"
        android:layout_alignParentEnd="true"
        android:layout_centerVertical="true"
        android:layout_marginEnd="10dp"
        android:scaleType="fitCenter"
        android:background="@drawable/delete_bg"
        android:visibility="gone"/>
</RelativeLayout>

上述代码中,RelativeLayout 是根布局。TextView 用于显示列表项标题,它的宽度填满整个布局,但是距离左、右边缘各留出一些间隙。ImageView 用于表示删除控件,它的宽度为 50dp、高度为 30dp。删除控件隐藏起来,在进入删除模式后变为可见状态。

  1. 监听列表项的点击事件

在 Adapter 中,为每个列表项定义一个监听器,以响应用户的点击事件。当按下删除控件时,调用一个接口方法 onDeleteClick,将列表项的位置作为参数传递。

示例代码:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    ...
    private OnDeleteListener onDeleteListener;
    public void setOnDeleteListener(OnDeleteListener l) {
        this.onDeleteListener = l;
    }
    public interface OnDeleteListener {
        void onDeleteClick(int position);
    }
    ...
    public class ViewHolder extends RecyclerView.ViewHolder {
            ...
            public ViewHolder(View itemView) {
                super(itemView);
                ...
                itemTitle.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (onDeleteListener != null) {
                            onDeleteListener.onDeleteClick(getAdapterPosition());
                        }
                    }
                });
                itemDelete.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (onDeleteListener != null) {
                            onDeleteListener.onDeleteClick(getAdapterPosition());
                        }
                    }
                });
            }
            ...
        }
}

在这个示例中,MyAdapter 中定义了一个嵌套接口 OnDeleteListener,用于监听删除事件。ViewHolder 是用于渲染视图的内部类,其中注册了一个 onclickListener,响应用户单击事件。当按下删除控件时,调用接口方法 onDeleteClick,传入列表项的位置作为参数。

  1. 进入删除模式

在 onDeleteClick 回调方法中,可以通过对 itemDelete 控件进行动画操作,使它颤动起来、背景变蓝,并且执行上面定义的动画效果。那么如何触发这个动画呢?

一种可行的策略是,在 Adapter 的 onBindViewHolder 方法中判断当前处于什么模式,同时更新列表项的布局和视觉效果。当 isEditMode 为真时,应该显示 itemDelete 控件,调用 setVisibility 即可;当 isEditMode 为假时应该隐藏 itemDelete 控件。

示例代码:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    ...
    private boolean isEditMode = false;
    public void setEditMode(boolean editMode) {
        isEditMode = editMode;
        notifyDataSetChanged();
    }
    ...
    @Override
    public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {
        ItemData itemData = list.get(position);
        holder.itemTitle.setText(itemData.getTitle());
        if (isEditMode) {
            holder.itemDelete.setVisibility(View.VISIBLE);
            holder.itemTitle.setPadding(0,0,holder.itemView.getResources().getDimensionPixelSize(R.dimen.dp_50),0);
        } else {
            holder.itemDelete.setVisibility(View.GONE);
            holder.itemTitle.setPadding(0,0,0,0);
        }
    }
}

上述代码中,MyAdapter 中定义了一个 boolean 类型的成员变量 isEditMode,记录当前是否处于删除模式。同时 MyAdapter 中提供了一个 setEditMode 方法,用于切换删除模式,并刷新视图。在 onBindViewHolder 方法中,根据 isEditMode 的值更新视觉效果。当 isEditMode 为 true 时,显示 itemDelete 控件,并将标题文本的 paddingRight 设为 50dp;否则隐藏该控件,标题文本的 padding 均为 0。

  1. 实现删除操作

在 onDeleteClick 回调方法中,获取列表项的位置,并使用 RecyclerView.Adapter 的 remove(position) 方法从列表中删除该项。同时还需要更新 MyAdapter 中的数据源 list,否则将造成数据不一致的情况。

示例代码:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    ...
    public void remove(int position) {
        list.remove(position);
        notifyItemRemoved(position);
    }
    ...
}

在上述代码中,MyAdapter 添加了一个 remove 方法,用于从列表中删除指定位置的项。在方法中,先从 list 中删除该项,并使用 notifyItemRemoved 方法通知 RecyclerView 做相应的 item 移除操作。

  1. 完善删除效果

当调用 remove 方法后,列表项会抖动出现动画效果,但是该项实际上还没有从列表中彻底删除。此时应该等动画执行完毕后,再将该项从列表中删除。

在 MyAdapter 中添加一个标志位 isAnimationPlaying,用于表示动画是否正在播放。在 onDeleteClick 回调中,调用 remove 方法时,将该位设置为 true。在动画结束后,再将该位设置为 false,并将删除模式置为假。

示例代码:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    ...
    private boolean isAnimationPlaying = false;
    ...
    public void remove(final int position) {
        if (isAnimationPlaying) return;
        isAnimationPlaying = true;
        final View itemView = layoutManager.findViewByPosition(position);
        final Animator animator = AnimatorInflater.loadAnimator(context, R.animator.delete_animation);
        animator.setTarget(itemView);
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }
            @Override
            public void onAnimationEnd(Animator animation) {
                list.remove(position);
                notifyItemRemoved(position);
                isAnimationPlaying = false;
                if (list.isEmpty()) {
                    if (onEmptyListener != null) {
                        onEmptyListener.onEmpty();
                    }
                }
                setEditMode(false);
            }
            @Override
            public void onAnimationCancel(Animator animation) {
            }
            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        });
        animator.start();
    }
    ...
}

在上述代码中,在 remove 方法中,如果 isAnimationPlaying 为 true,直接返回。否则将其设为 true,并通过 layoutManager 的 findViewByPosition 方法获取该项的视图对象。接着加载 delete_animation.xml,并添加 AnimatorListener。在 onAnimationEnd 回调中,将该项从列表中删除,并将 isAnimationPlaying 设为 false,即删除动画已播放完毕。如果列表为空,则通过 OnEmptyListener 回调,通知调用者列表已经为空,并切换到非删除模式。

  1. 案例总结

通过上述步骤,我们实现了在 RecyclerView 中添加删除模式的效果,包括选项背景变蓝、动画抖动和删除和列表项的完整删除。在整个实现过程中,需要注意的是,我们要正确记录当前处于什么模式,并根据这个状态更新布局、视觉效果和删除操作。还需要使用动画集合资源和听众来实现删除动画的效果,同时处理好动画结束后的后续操作。这些细节可以在实际开发中进一步优化和维护。