1. Anroid 提供API关于 拖拽、侧滑
Android ItemTouchHelper.Callback API认识:
final ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback); callbak 使用ItemTouchHelper 包装
传递给: itemTouchHelper.attachToRecyclerView(mRecyclerView);
// 设置用户监听动作方向,比如上下拖动、水平滑动
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
}
// 当拖拽 item 移动的时候回调,回调以后可以用于数据交换
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder srcHolder, RecyclerView.ViewHolder targetViewHolder) {
}
// 当Item 侧滑的时候回调
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}
// 当Item 拖拽被选中的时候回调
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
}
// 当item 被删除的时候回调
// 比如交换位置,从原来位置删除,在新位置上绘制
// 比如 item 侧滑被删除的时候
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
}
// 当child 绘制的时候
// 比如拖动、侧滑,Item的状态需要不断的绘制
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
}
// 是否允许长按拖拽效果,item默认支持返回true即可
@Override
public boolean isLongPressDragEnabled() {
return true;
}
2. 实现上下拖拽、并且松开以后刷新数据
2.1. 开启监听上下拖拽 ,实现 ItemTouchHelper.Callback 接口回调方法
// 1. 用于监听那个方向的拖动
// 先上、先下、左、右
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int up= ItemTouchHelper.UP;
int down = ItemTouchHelper.DOWN;
int left = ItemTouchHelper.LEFT;
int right =ItemTouchHelper.RIGHT;
// 我要监听拖拽的方向
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
// 要监听 swiper 侧滑是哪个方向
int swipeFlags= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
int flasg = makeMovementFlags(dragFlags,swipeFlags);
return flasg;
}
2. 设置item可以支持上下拖拽功能
// 重写这个方法以后item那么就支持 长按拖拽了
// 3. 是否允许长按 拖拽效果
@Override
public boolean isLongPressDragEnabled() {
return true;
}
// 不用上面item直接拖拽,使用item中的某一个imageView来实现拖拽效果,那么需要把ViewHolder中某一个控件的
3. 那么如何设置按下item中的 imageView 实现拖拽 item的效果
// 不用上面item直接拖拽,使用item中的某一个imageView来实现拖拽效果,
那么需要监听到ViewHolder中某一个控件的被 MotionEvent.ACTION_DOWN ,把ViewHoldr传递给
itemTouchHelper.attachToRecyclerView(mRecyclerView);
MyAdapter 实现代码: 内层代码
StartDragListener startDragListener;
public void setStartDragListener(StartDragListener startDragListener) {
this.startDragListener = startDragListener;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
Log.e(TAG, "set value to item:" + position);
holder.title.setText(datas.get(position));
// 监听按下事件,一直按下,一直监听, 监听ImageView的按下时间
holder.rv_main_image.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
// 传递给谁
startDragListener.onStartDrag(holder);
}
return false;
}
});
}
MyActivity外出代码:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 设置 按下ViewHolder中的ImageView实现 拖拽效果
mMyAdapter.setStartDragListener(new StartDragListener() {
@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
itemTouchHelper.startDrag(viewHolder);
}
});
}
4. 如何在拖拽的时候刷新数据
// 2. ItemTouchHelper.Callback 当拖拽 Item 移动的时候回调
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder srcHolder, RecyclerView.ViewHolder targetViewHolder) {
// 相同条目不进行交换
if(srcHolder.getItemViewType()!=targetViewHolder.getItemViewType()){
return false;
}
// 回调把参数传递外外面去,在外面实现方法的回调
// 返回在,外面执行方法的返回值
boolean flag= itemTouchMoveListener.onItemMove(srcHolder.getAdapterPosition(),targetViewHolder.getAdapterPosition());
return flag;
}
5. MainActivity中 监听拖拽,交换数据
MyItemTouchHelperCallback callback=new MyItemTouchHelperCallback();
// 监听拖拽 刷新数据, 把拖拽位置传递出来
callback.setItemTouchMoveListener(new ItemTouchMoveListener() {
@Override
public boolean onItemMove(int fromPositon, int toPosition) {
// 数据交换
Collections.swap(datas,fromPositon,toPosition);
mMyAdapter.notifyItemMoved(fromPositon,toPosition);
return true;
}
});
效果图:
======================================================================
设置选中的时候设置颜色,没有选中的时候去掉颜色
// Item 被选中回调
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// 判断选中
if(actionState != ItemTouchHelper.ACTION_STATE_IDLE ){
viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getResources().getColor(R.color.colorPrimary));
}
// 松开的时候要复原
super.onSelectedChanged(viewHolder, actionState);
}
// 松开的时候要复原
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// 默认白色
viewHolder.itemView.setBackgroundColor(Color.WHITE);
super.clearView(recyclerView, viewHolder);
}
======================================================================
侧滑动画设置: 回调函数onChildDraw【绘制ViewHolder的时候回调】
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
// 只是侧滑的时候起作用
if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
// dx 就是从 0- View.getWidth
// 转化透明度 0 ~1
// 1减去,那么就是 1-0了 , 不透明度1 显示 不透明度0,透明度0 不显示
float alphaValue= 1- Math.abs(dX/viewHolder.itemView.getWidth());
Log.e("denganzhi1",alphaValue+"");
viewHolder.itemView.setAlpha(1);
// 属性动画就是简单
viewHolder.itemView.setScaleX(1);
viewHolder.itemView.setScaleY(1);
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
侧滑绘制以后有空白部分问题?
引申: ListViwe 和 RecyclerView 都有复用问题,
比如有 checkbox的时候ListView,如果一个item改变了checkbox,那么在滑动的时候该item的复用checkbox也会改变
****** 被复用的ViewHoder复用以后,要恢复默认属性
解决实例1:当View隐藏的时候恢复该ViewHolder的默认数据:
// 正确理解,当ViewHolder的View被删除的时候,
// 如果交换位置,那么交换位置结束了,那么View从原来的位置删除,在新位置绘制
// 松开的时候要复原
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// 默认白色
viewHolder.itemView.setBackgroundColor(Color.WHITE);
// viewHolder.itemView.setAlpha(1);
// // 属性动画就是简单
// viewHolder.itemView.setScaleX(1);
// viewHolder.itemView.setScaleY(1);
super.clearView(recyclerView, viewHolder);
}
或者解决方案:
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
// 只是侧滑的时候起作用
// dx 就是从 0- View.getWidth
// 转化透明度 0 ~1
// 1减去,那么就是 1-0了 , 不透明度1 显示 不透明度0,透明度0 不显示
float alphaValue= 1- Math.abs(dX/viewHolder.itemView.getWidth());
if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
Log.e("denganzhi1",alphaValue+"");
viewHolder.itemView.setAlpha(1);
// 属性动画就是简单
viewHolder.itemView.setScaleX(1);
viewHolder.itemView.setScaleY(1);
}
// 用完以后回复
if(alphaValue==0){
viewHolder.itemView.setAlpha(1);
// 属性动画就是简单
viewHolder.itemView.setScaleX(1);
viewHolder.itemView.setScaleY(1);
}
// 隐藏以后调用super 删除View
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
************************************************************************************************
类视QQ的 条目侧滑一半效果实现:
**** 未实现???
// 判断是否超出或者达到 width/2, 那么让 setTranslationX位一半位置
// 默认 在滑动的不断调用 super.onChildDraw去 绘制
// 那么在 一半的时候不要调用super.onChildDraw 方法,那么就暂停在这里了
if(Math.abs(dX) <= viewHolder.itemView.getWidth()/2 ){
viewHolder.itemView.setTranslationX((-0.5f* viewHolder.itemView.getWidth()));
}else{
viewHolder.itemView.setTranslationX(dX);
}
// super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
**** 思路2:
ItemView设置成功一个ViewPager,左右2个View
************************************************************************************************
3. 实现侧滑功能
MyItemTouchHelperCallback 重写方法
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int up= ItemTouchHelper.UP;
int down = ItemTouchHelper.DOWN;
int left = ItemTouchHelper.LEFT;
int right =ItemTouchHelper.RIGHT;
// 我要监听拖拽的方向
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
// 要监听 swiper 侧滑是哪个方向
int swipeFlags= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
int flasg = makeMovementFlags(dragFlags,swipeFlags);
return flasg;
}
// 7. 监听侧滑
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// 侧滑回调,刷新数据
itemTouchRemoveListener.onItemReMove(viewHolder.getAdapterPosition());
}
MainActivity 中实现回调,刷新数据
// 自定义回调
callback.setItemTouchRemoveListener(new ItemTouchRemoveListener() {
@Override
public boolean onItemReMove(int position) {
datas.remove(position);
mMyAdapter.notifyItemRemoved(position);
return true;
}
});