照例,我们感谢一下技术大牛的分享,只有他们的无私分享,才让后来者更好地学习。
RecyclerViewItemTouchHelperDemo【使用ItemTouchHelper进行拖拽排序功能】
本文基于该文章进行学习。
首先,RecyclerView在Android的support库里,所以要使用的时候需要先在build.gradle内添加依赖,如果项目中有引用appcompat的话,版本号和appcompat保持一致
dependencies {
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
然后因为我们在拖拽的时候,会有震动效果,所以在AndroidManifest.xml里添加权限
<uses-permission android:name="android.permission.VIBRATE" />
为了方便数据的存放和读取,我们需要创建一个Bean类
ChannelBean.java
public class ChannelBean {
private String channelId;
private String channelNamee;
private int channelImage;
public int getChannelImage() {
return channelImage;
}
public String getChannelId() {
return channelId;
}
public String getChannelNamee() {
return channelNamee;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public void setChannelImage(int channelImage) {
this.channelImage = channelImage;
}
public void setChannelNamee(String channelNamee) {
this.channelNamee = channelNamee;
}
}
有了Bean之后,我们开始设置adapter和item布局
首先先创建item布局,因为adapter需要引用到该布局文件
channel_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/listitem_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/linear_01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:background="@drawable/yuanjiao_10"
android:paddingTop="10dp"
android:paddingBottom="10dp">
>
<ImageView
android:id="@+id/img_icon_1"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.3"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/text_icon_1"
android:src="@mipmap/icon_01"/>
<TextView
android:id="@+id/text_icon_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="留言信息"
app:layout_constraintTop_toBottomOf="@+id/img_icon_1"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
然后创建Adapter。在adapter中,我们需要获得上下文和项目集合(频道集合)。因为我们继承了RecyclerView.Adapter<RecyclerView.ViewHolder>,所以我们需要实现三个方法,分别为
onCreateViewHolder,onBindViewHolder和getItemCount。
首先是onCreateViewHolder,从名字可以看出是用来创建viewHolder的。所以我们先要根据item.xml确定有哪些view需要获取到,然后声明一个ItemViewHolder,然后在onCreateViewHolder内实例化。本文中有四个view可以获取,分别为LinearLayout,ConstraintLayout,ImageView和TextView。所以我们声明viewHolder继承RecyclerView.ViewHolder
//声明grid列表项ViewHolder
private class ItemViewHolder extends RecyclerView.ViewHolder {
public ItemViewHolder(@NonNull View itemView) {
super(itemView);
listitemLayout = (LinearLayout)itemView.findViewById(R.id.listitem_layout);
linear_01 = (ConstraintLayout)itemView.findViewById(R.id.linear_01);
img_icon_1 = (ImageView)itemView.findViewById(R.id.img_icon_1);
text_icon_1 = (TextView)itemView.findViewById(R.id.text_icon_1);
}
LinearLayout listitemLayout;
ConstraintLayout linear_01;
ImageView img_icon_1;
TextView text_icon_1;
}
然后在onCreateViewHolder中,我们实例化这个viewHolder并制定布局文件
//创建ViewHolder
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(myContext).inflate(R.layout.channel_item,parent,false);
ItemViewHolder itemViewHolder = new ItemViewHolder(view);
return itemViewHolder;
}
创建好viewHolder之后,我们需要给他绑定数据,从名字可以知道,调用onBindViewHolder
//将数据绑定在ViewHolder上
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int index) {
//判定列表项还是上拉加载区域
if(holder instanceof ItemViewHolder){
ChannelBean channelBean = listitemList.get(index);
final ItemViewHolder itemViewHolder = ((ItemViewHolder)holder);
itemViewHolder.text_icon_1.setText(channelBean.getChannelNamee());
itemViewHolder.img_icon_1.setImageResource(channelBean.getChannelImage());
}
}
绑定好数据之后,我们还需要他有点击监听的事件,所以我们需要添加OnItemClickListener回调
/*==================添加OnItemClickListener回调==============*/
public interface OnItemClickListener{
void onItemClick(View view,int position);
void onItemLongClick(View view,int position);
}
private OnItemClickListener mOnItemClickListener;
public void setOnItemClickListener(OnItemClickListener mOnItemClickListener){
this.mOnItemClickListener = mOnItemClickListener;
}
这里的回调设置为接口,在具体调用的时候实现。
添加好OnItemClickListener回调之后,我们需要在onBindViewHolder里绑定点击事件
//将数据绑定在ViewHolder上
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int index) {
//判定列表项还是上拉加载区域
if(holder instanceof ItemViewHolder){
ChannelBean channelBean = listitemList.get(index);
final ItemViewHolder itemViewHolder = ((ItemViewHolder)holder);
itemViewHolder.text_icon_1.setText(channelBean.getChannelNamee());
itemViewHolder.img_icon_1.setImageResource(channelBean.getChannelImage());
//如果设置了回调,则设置了点击事件
if(mOnItemClickListener != null){
itemViewHolder.listitemLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = itemViewHolder.getLayoutPosition();//增加或删除数据时,position和index就不一样了
mOnItemClickListener.onItemClick(itemViewHolder.listitemLayout,position);
}
});
itemViewHolder.listitemLayout.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int position = itemViewHolder.getLayoutPosition();
mOnItemClickListener.onItemLongClick(itemViewHolder.listitemLayout,position);
return false;
}
});
}
}
}
然后在具体调用的时候实现void onItemClick(View view,int position); void onItemLongClick(View view,int position);这两个接口
因为考虑到item拖拽的时候,不能跨RecuclerView(未学习到),所以设置为点击item添加和删除,这时候我们就需要一个additem和一个removeitem方法了。
//添加item 用于动画表现
public void addItem(int position,ChannelBean listitemBean){
listitemList.add(position,listitemBean);
notifyItemChanged(position);
}
//删除item 用于动画表现
public void removeItem(int position){
listitemList.remove(position);
notifyItemChanged(position);
}
至此,adapter已经完成。完整的adapter文件为
ChannelAdapter.java
public class ChannelAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
//上下文
private Context myContext;
//频道集合
private ArrayList<ChannelBean> listitemList;
//构造函数
public ChannelAdapter(Context context, ArrayList<ChannelBean> itemlist){
this.myContext = context;
this.listitemList = itemlist;
}
//创建ViewHolder
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(myContext).inflate(R.layout.channel_list_item,parent,false);
ItemViewHolder itemViewHolder = new ItemViewHolder(view);
return itemViewHolder;
}
//将数据绑定在ViewHolder上
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int index) {
//判定列表项还是上拉加载区域
if(holder instanceof ItemViewHolder){
ChannelBean channelBean = listitemList.get(index);
final ItemViewHolder itemViewHolder = ((ItemViewHolder)holder);
itemViewHolder.text_icon_1.setText(channelBean.getChannelNamee());
itemViewHolder.img_icon_1.setImageResource(channelBean.getChannelImage());
//如果设置了回调,则设置了点击事件
if(mOnItemClickListener != null){
itemViewHolder.listitemLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = itemViewHolder.getLayoutPosition();//增加或删除数据时,position和index就不一样了
mOnItemClickListener.onItemClick(itemViewHolder.listitemLayout,position);
}
});
itemViewHolder.listitemLayout.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int position = itemViewHolder.getLayoutPosition();
mOnItemClickListener.onItemLongClick(itemViewHolder.listitemLayout,position);
return false;
}
});
}
}
}
//获取总的条目数
@Override
public int getItemCount() {
return listitemList.size();
}
//声明grid列表项ViewHolder
private class ItemViewHolder extends RecyclerView.ViewHolder {
public ItemViewHolder(@NonNull View itemView) {
super(itemView);
listitemLayout = (LinearLayout)itemView.findViewById(R.id.listitem_layout);
linear_01 = (ConstraintLayout)itemView.findViewById(R.id.linear_01);
img_icon_1 = (ImageView)itemView.findViewById(R.id.img_icon_1);
text_icon_1 = (TextView)itemView.findViewById(R.id.text_icon_1);
}
LinearLayout listitemLayout;
ConstraintLayout linear_01;
ImageView img_icon_1;
TextView text_icon_1;
}
//添加item 用于动画表现
public void addItem(int position,ChannelBean listitemBean){
listitemList.add(position,listitemBean);
notifyItemChanged(position);
}
//删除item 用于动画表现
public void removeItem(int position){
listitemList.remove(position);
notifyItemChanged(position);
}
/*==================添加OnItemClickListener回调==============*/
public interface OnItemClickListener{
void onItemClick(View view,int position);
void onItemLongClick(View view,int position);
}
private OnItemClickListener mOnItemClickListener;
public void setOnItemClickListener(OnItemClickListener mOnItemClickListener){
this.mOnItemClickListener = mOnItemClickListener;
}
}
接下来我们来看具体调用方法。
我们新建一个activity--TestRecyclerView,得到TestRecyclerView.java和activity_test_recycler_view.xml
我们先设置xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TestRecyclerView">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:cacheColorHint="#00000000"
android:divider="@null"
android:listSelector="#00000000"
android:scrollbars="none"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/recycler_view2"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:cacheColorHint="#00000000"
android:divider="@null"
android:listSelector="#00000000"
android:scrollbars="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/recycler_view"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
这里我们设置了两个recyclerview,主要是为了加上点击增加和删除的功能。
首先,我们先声明RecyclerView,ArrayList<ChannelBean>,ChannelAdapter,分别声明两个。
然后在onCreate调用三个方法,initViews,initDatas,initEvents,三个方法分别用于初始化控件view,初始化数据data,还有初始化事件event(也可以理解为绑定事件)。
initViews方法的实现只需要通过id获取两个RecyclerView就可以了
private void initViews() {
mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView2 = findViewById(R.id.recycler_view2);
}
然后我们需要设置view的数据。首先声明ArrayList<ChannelBean>,然后通过for循环给list赋值(例子需要。实际中可以网络获取data然后输入。)。获得数据之后,我们还需要给recyclerview指定布局管理器。常见的布局管理器有LinearLayoutManager,GridLayoutManager和StaggeredGridLayoutManager,分别对应列表布局,表格布局和瀑布流布局(瀑布流布局是一个很好用的布局,做图片手机网站的时候可以使用这种模式。目前国内的图片网站最常用的就是瀑布流。例如花瓣。当然,花瓣是网页的,只是形式上使用的是瀑布流的布局而已。)
因为我们有两个recyclerView,所以要设置两次。这里只举例一次。
private void initDatas() {
//初始化集合
mChannelBeanArrayList = new ArrayList<ChannelBean>();
for (int i = 0;i<5;i++){
ChannelBean channelBean = new ChannelBean();
channelBean.setChannelId("id:"+i);
channelBean.setChannelImage(getResources().getIdentifier("icon_0"+(i+1),"mipmap",getPackageName()));
channelBean.setChannelNamee("图标"+i);
mChannelBeanArrayList.add(channelBean);
}
//设置布局管理器
GridLayoutManager gridLayoutManager = new GridLayoutManager(this,3);
mRecyclerView.setLayoutManager(gridLayoutManager);
//设置适配器
if (mChannelAdapter == null){
mChannelAdapter = new ChannelAdapter(this,mChannelBeanArrayList);
mRecyclerView.setAdapter(mChannelAdapter);
//添加分割线
//设置添加删除动画
//调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
mRecyclerView.setSelected(true);
}else {
mChannelAdapter.notifyDataSetChanged();
}
}
隐藏的知识点:当我们的drawable文件的命名是符合规律的,然后我们需要循环调用的时候该怎么办,可以通过
getResources().getIdentifier("icon_0"+(i+1),"mipmap",getPackageName())
来循环获取图片id。第一个参数为图片命名的规律,第二个为R文件的类型。可以是“mipmap”,“drawable”,“id”等。
接下来,我们要设置点击事件。也就是初始化events了。
逻辑也简单,当我们点击recyclerview1的item时,先往recyclerview2添加该item,然后删除recyclerview1里的item
private void initEvents() {
//列表适配器的点击监听事件
mChannelAdapter.setOnItemClickListener(new ChannelAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(TestRecyclerView.this,mChannelBeanArrayList.get(position).getChannelNamee(),Toast.LENGTH_SHORT).show();
mChannelAdapter2.addItem(mChannelBeanArrayList2.size(),mChannelBeanArrayList.get(position));
mChannelAdapter2.notifyDataSetChanged();
mChannelAdapter.removeItem(position);
mChannelAdapter.notifyDataSetChanged();
}
@Override
public void onItemLongClick(View view, int position) {
currentPagePosition = position;//拖拽时给它赋值。
Toast.makeText(TestRecyclerView.this,mChannelBeanArrayList.get(position).getChannelNamee()+"长按",Toast.LENGTH_SHORT).show();
}
});
mChannelAdapter2.setOnItemClickListener(new ChannelAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(TestRecyclerView.this,mChannelBeanArrayList2.get(position).getChannelNamee(),Toast.LENGTH_SHORT).show();
if (mChannelBeanArrayList.size()<5){
mChannelAdapter.addItem(mChannelBeanArrayList.size(),mChannelBeanArrayList2.get(position));
mChannelAdapter.notifyDataSetChanged();
mChannelAdapter2.removeItem(position);
mChannelAdapter2.notifyDataSetChanged();
}
}
@Override
public void onItemLongClick(View view, int position) {
}
});
}
这样,我们运行的时候,就可以看到点击删除item和增加item了。
什么,拖拽呢?不要急,接下来就是拖拽功能的集成。
我们还是在initEvent方法内调用一个新的方法。initItemTouchHelper();
调用之后,我们来实现这个方法。
首先,实现itemTouchHelper方法之前,我们需要在声明几个变量。
分别是ItemTouchHelper,currentPagePosition,currentPageNewPosition和newOrder四个参数。
private ItemTouchHelper itemTouchHelper;
private int currentPagePosition = -1;//当前拖拽的item的初始位置,从零开始【长按时赋值】,用来和currentPageNewPosition对比进行判断是否执行排序接口
private int currentPageNewPosition = -1;//当前item拖拽后的位置,从0开始
private boolean newOrder = false;//标记是否拖拽排序过,默认是false
然后我们在initItemTouchHelper里,我们必须实现的有三个方法,onMovementFlags,onMove,onSwiped,onMovementFlags函数主要用于设置是否处理拖拽和滑动事件,并返回拖拽和滑动的操作方向。
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
int dragFlags = 0;//dragFlags 是拖拽标志
int swipeFlags = 0;//swipeFlags 是侧滑标志,我们把swipeFlags设置为0,表示不处理侧滑
if (recyclerView.getLayoutManager() instanceof GridLayoutManager){
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
swipeFlags = 0;
}else {
dragFlags = 0;
swipeFlags = 0;
}
return makeMovementFlags(dragFlags,swipeFlags);
}
因为我们不处理滑动事件,所以不处理onSwiped方法,接下来我们实现onMove方法
首先我们先获取item原先的position和移动之后所处位置的position。然后当移动后的position大于原先的position,我们将这两个中间的所有item的position都减1.如果移动后的position小于原先的position,我们将这两个item中间的所有item的position都加1。最后我们需要调用一个方法mChannelAdapter.notifyItemMoved(fromPosition,toPosition);
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
//添加判断,实现某一项不可交换
if(fromPosition<toPosition){
for (int i = fromPosition; i<toPosition;i++){
Collections.swap(mChannelBeanArrayList,i,i+1);
}
}else {
for (int i = fromPosition; i>toPosition;i--){
Collections.swap(mChannelBeanArrayList,i,i-1);
}
}
mChannelAdapter.notifyItemMoved(fromPosition,toPosition);
return true;
}
这时候我们已经实现了拖拽方法了,但是为了我们拖拽项目的时候更加明显,所以我们添加一个效果,当我们长按item进行拖拽的时候,产生震动,并让背景颜色发生改变。当我们松开手指停止拖拽的时候,我们将样式还原。
/**
* 当我们希望拖拽的item在拖拽过程中发生震动或者颜色变深,需要重写下面两个方法
* 当长按item的时候(拖拽开始的时候)调用
* ACTION_STATE_IDLE; 闲置状态
* ACTION_STATE_SWIPE; 滑动状态
* ACTION_STATE_DRAG; 拖拽状态
*/
@Override
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG){
//获取系统震动服务
Vibrator vib = (Vibrator) TestRecyclerView.this.getSystemService(Service.VIBRATOR_SERVICE);
//震动70毫秒
vib.vibrate(70);
viewHolder.itemView.setPressed(true);
//设置拖动时的背景颜色
viewHolder.itemView.setBackgroundColor(Color.parseColor("#FF0000"));
}
super.onSelectedChanged(viewHolder, actionState);
}
//当手指松开的时候(拖拽或滑动完成时)调用,这时候我们将item恢复为原来的状态。
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setPressed(false);
currentPageNewPosition = viewHolder.getAdapterPosition();
if (!(currentPagePosition == currentPageNewPosition)){
newOrder = true;
//执行其他方法,比如设置拖拽后的item为选中状态等,暂时没有想到其他有用的效果
}
viewHolder.itemView.setBackground(null);
//解决重叠问题
mChannelAdapter.notifyDataSetChanged();
}
这样我们就设置好了拖拽和滑动的动作,然后我们要将这个itemTouchHelper添加到recyclerview里,
//设置是否可以排序
itemTouchHelper.attachToRecyclerView(mRecyclerView);
其中,我们可以看到我们只对recyclerview1进行排序,并且在onMove里只对ArrayList1和adapter1进行更改,所以我们的拖拽功能只对recyclerview1起效。
完整的TestRecyclerView.java为
public class TestRecyclerView extends AppCompatActivity {
private RecyclerView mRecyclerView;
private ArrayList<ChannelBean> mChannelBeanArrayList;
private ChannelAdapter mChannelAdapter;
private RecyclerView mRecyclerView2;
private ArrayList<ChannelBean> mChannelBeanArrayList2;
private ChannelAdapter mChannelAdapter2;
/**
* 拖拽功能
* @param savedInstanceState
*/
private ItemTouchHelper itemTouchHelper;
private int currentPagePosition = -1;//当前拖拽的item的初始位置,从零开始【长按时赋值】,用来和currentPageNewPosition对比进行判断是否执行排序接口
private int currentPageNewPosition = -1;//当前item拖拽后的位置,从0开始
private boolean newOrder = false;//标记是否拖拽排序过,默认是false
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_recycler_view);
//分别为初始化控件,初始化数据和初始化事件
initViews();
initDatas();
initEvents();
}
private void initEvents() {
//列表适配器的点击监听事件
mChannelAdapter.setOnItemClickListener(new ChannelAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(TestRecyclerView.this,mChannelBeanArrayList.get(position).getChannelNamee(),Toast.LENGTH_SHORT).show();
mChannelAdapter2.addItem(mChannelBeanArrayList2.size(),mChannelBeanArrayList.get(position));
mChannelAdapter2.notifyDataSetChanged();
mChannelAdapter.removeItem(position);
mChannelAdapter.notifyDataSetChanged();
}
@Override
public void onItemLongClick(View view, int position) {
currentPagePosition = position;//拖拽时给它赋值。
Toast.makeText(TestRecyclerView.this,mChannelBeanArrayList.get(position).getChannelNamee()+"长按",Toast.LENGTH_SHORT).show();
}
});
mChannelAdapter2.setOnItemClickListener(new ChannelAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(TestRecyclerView.this,mChannelBeanArrayList2.get(position).getChannelNamee(),Toast.LENGTH_SHORT).show();
if (mChannelBeanArrayList.size()<5){
mChannelAdapter.addItem(mChannelBeanArrayList.size(),mChannelBeanArrayList2.get(position));
mChannelAdapter.notifyDataSetChanged();
mChannelAdapter2.removeItem(position);
mChannelAdapter2.notifyDataSetChanged();
}
}
@Override
public void onItemLongClick(View view, int position) {
}
});
//设置完数据之后,开始初始化拖拽事件
initItemTouchHelper();
}
private void initDatas() {
//初始化集合
mChannelBeanArrayList = new ArrayList<ChannelBean>();
mChannelBeanArrayList2 = new ArrayList<ChannelBean>();
for (int i = 0;i<5;i++){
ChannelBean channelBean = new ChannelBean();
ChannelBean channelBean2 = new ChannelBean();
channelBean.setChannelId("id:"+i);
channelBean.setChannelImage(getResources().getIdentifier("icon_0"+(i+1),"mipmap",getPackageName()));
// channelBean.setChannelImage(R.mipmap.icon_01);
channelBean.setChannelNamee("图标"+i);
channelBean2.setChannelId("id2:"+i);
channelBean2.setChannelImage(getResources().getIdentifier("icon_0"+(i+1),"mipmap",getPackageName()));
// channelBean.setChannelImage(R.mipmap.icon_01);
channelBean2.setChannelNamee("图标22"+i);
mChannelBeanArrayList.add(channelBean);
mChannelBeanArrayList2.add(channelBean2);
}
//设置布局管理器
GridLayoutManager gridLayoutManager = new GridLayoutManager(this,3);
mRecyclerView.setLayoutManager(gridLayoutManager);
GridLayoutManager gridLayoutManager2 = new GridLayoutManager(this,3);
mRecyclerView2.setLayoutManager(gridLayoutManager2);
//设置适配器
if (mChannelAdapter == null){
mChannelAdapter = new ChannelAdapter(this,mChannelBeanArrayList);
mRecyclerView.setAdapter(mChannelAdapter);
//添加分割线
//设置添加删除动画
//调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
mRecyclerView.setSelected(true);
}else {
mChannelAdapter.notifyDataSetChanged();
}
if (mChannelAdapter2 == null){
mChannelAdapter2 = new ChannelAdapter(this,mChannelBeanArrayList2);
mRecyclerView2.setAdapter(mChannelAdapter2);
//添加分割线
//设置添加删除动画
//调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
mRecyclerView2.setSelected(true);
}else {
mChannelAdapter2.notifyDataSetChanged();
}
}
private void initItemTouchHelper() {
//拖拽
itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
//开启长按拖拽功能,默认为true【暂时用不到】
//如果需要我们开始自定义拖拽和滑动,可以设置为false,然后调用itemTouchHelper.startDrag(ViewHolder)方法来开启
@Override
public boolean isLongPressDragEnabled() {
return true;
}
//开启滑动功能,默认为true【暂时用不到】
//如果需要我们自定义拖拽和滑动,可以设置为false,然后调用itemTouchHlper.startDrag(ViewHolder)方法来开启
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
/**
* 用于设置是否处理拖拽事件和滑动事件,以及拖拽和滑动的操作方向。
* 如果是列表的recyclerview,则拖拽事件只有up和down两个方向。
* 如果是网格类型的则有up,down,left,right四个方向
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
int dragFlags = 0;//dragFlags 是拖拽标志
int swipeFlags = 0;//swipeFlags 是侧滑标志,我们把swipeFlags设置为0,表示不处理侧滑
if (recyclerView.getLayoutManager() instanceof GridLayoutManager){
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
swipeFlags = 0;
}else {
dragFlags = 0;
swipeFlags = 0;
}
return makeMovementFlags(dragFlags,swipeFlags);
}
/**
* 如果设置了非 0 的dragFlags,当我们长按item的时候就会进入拖拽并在拖拽过程中不断回调onMove方法
* 我们在这个方法里获取当前拖拽的item和已经被拖拽到所处位置的item的viewholder,
* 有了这2个viewhol,我们就可以交换他们的数据集并调用Adapter的notifyItemMoved方法来刷新item
* @param recyclerView
* @param viewHolder
* @param target
* @return
*/
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
//添加判断,实现某一项不可交换
if(fromPosition<toPosition){
for (int i = fromPosition; i<toPosition;i++){
Collections.swap(mChannelBeanArrayList,i,i+1);
}
}else {
for (int i = fromPosition; i>toPosition;i--){
Collections.swap(mChannelBeanArrayList,i,i-1);
}
}
mChannelAdapter.notifyItemMoved(fromPosition,toPosition);
return true;
}
//如果我们设置了非 0 的swipeFlags,我们在侧滑的时候就会回调onswiped方法,我们不处理这个方法的话,就相当于没有侧滑事件
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
/**
* 当我们希望拖拽的item在拖拽过程中发生震动或者颜色变深,需要重写下面两个方法
* 当长按item的时候(拖拽开始的时候)调用
* ACTION_STATE_IDLE; 闲置状态
* ACTION_STATE_SWIPE; 滑动状态
* ACTION_STATE_DRAG; 拖拽状态
*/
@Override
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG){
//获取系统震动服务
Vibrator vib = (Vibrator) TestRecyclerView.this.getSystemService(Service.VIBRATOR_SERVICE);
//震动70毫秒
vib.vibrate(70);
viewHolder.itemView.setPressed(true);
//设置拖动时的背景颜色
viewHolder.itemView.setBackgroundColor(Color.parseColor("#FF0000"));
}
super.onSelectedChanged(viewHolder, actionState);
}
//当手指松开的时候(拖拽或滑动完成时)调用,这时候我们将item恢复为原来的状态。
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setPressed(false);
currentPageNewPosition = viewHolder.getAdapterPosition();
if (!(currentPagePosition == currentPageNewPosition)){
newOrder = true;
//执行其他方法,比如设置拖拽后的item为选中状态等,暂时没有想到其他有用的效果
}
viewHolder.itemView.setBackground(null);
//解决重叠问题
mChannelAdapter.notifyDataSetChanged();
}
});
//设置是否可以排序
itemTouchHelper.attachToRecyclerView(mRecyclerView);
}
private void initViews() {
mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView2 = findViewById(R.id.recycler_view2);
}
}