Android 自定义仿手机QQ横向滑动的RecyclerView
在我们的项目中,需要对列表的数据进行人性化的编辑查看与删除,与我一起工作的前辈写下了这些代码,在充分理解学习之后,我想将它保存在这里,并新增添加了注释。方便日后的使用和加深理解并希望能帮到更多的人.
/**
* Created by dly
*/
public class RemoveRecyclerView extends RecyclerView{
//上一次的触摸点
private int mLastX,mLastY;
//当前触摸的item的位置
private int mPostion;
//item所对应的布局
private LinearLayout mItemLayout;
//删除按钮,编辑按钮在同一个Layout下
private LinearLayout mLayoutItem;
private TextView mDelete;
private TextView mApproval;
//最大滑动距离(即两个按钮的宽度)
private int mMaxLength;
//是否在进行垂直滑动操作
private boolean isDragging;
//item 是否在跟随手指移动
private boolean isItemMoving;
//item是否开始自动滑动
private boolean isStartScroll;
//按钮状态 0 关闭 1将要关闭 2将要打开 3打开
private int mDeleteBtnState;
/**
* VelocityTracker 是一个专用的速度追踪对象
*/
private VelocityTracker mVelocityTracker;
private Scroller mScroller;
//定义一个点击事件监听器
private OnItemClickListener mListener;
private boolean isSupportRemove = true;
//三个构造方法
public RemoveRecylerView(Context context){this(context,null);}
public RemoveRecyclerView(Context context,AttributeSet attrs){
this(context,attrs,0);
}
public RemoveRecyclerView(Context context,AttributeSet attrs,int defStyle){
super(context,attrs,defStyle);
mContext = context;
mScroller = new Scroller(context, new LinearInterpolator());
mVelocityTracker = VelocityTracker.obtain();
}
//重点来了: 重写触摸动作的回调方法,这里没有去写事件分发dispathevent 而是直接重写ontouchevent方法 比在网上找的其他解决方案更加简洁
/**
return true: 标识该事件处理方法已完全处理该方法,该事件不会传播出去;
return false: 标识该事件处理方法未完全处理该方法, 该事件还会传播出去;
**/
@Override
public boolean onTouchEvent(MotionEvent e){
mVelocityTracker.addMovement(e);//捕捉对象速度
int x =(int)e.getX();
int y =(int)e.getY();
switch(e.getAction()){
case MotionEvent.ACTION_DOWN:
if(mDeleteBtnState == 0){
//RecyclerView所特有的方法,返回当前位置的item view
View view = findChildViewUnder(x,y);
if(view == null){
return false;
}
BaseViewHolder viewHolder = (BaseViewHolder)getChildViewHolder(view);
mItemLayout = viewHolder.getLayout();
mPosition = viewHolder.getAdapterPosition();
if(mItemLayout == null) return true;
mLayoutItme = (LinearLayout) mItemLayout.findViewById(R.id.layout_click);
mDelete = (TextView) mItemLayout.findViewById(R.id.leave_delete);
mApproval = (TextView) mItemLayout.findViewById(R.id.leave_approval);
mMaxLength = mLayoutItme.getWidth();
//对textView添加点击事件
mApprove.setOnClickListener(new OnClickListenr(){
@Override
public void onClick(View v){
if(mListener == null)return;
mListener.onApprovalClick(mPosition);
//点击事件完成后 将item归位 并将状态值归0
mItemLayout.scrollTo(0,0);
mDeleteBtnState = 0;
}
});
mDelete.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if (mListener == null) return;
mListener.onDeleteClick(mPosition);
mItemLayout.scrollTo(0, 0);
mDeleteBtnState = 0;
}
});
}else if(mDeleteBtnState == 3){
mScroller.startScroll(mItemLayout.getScrollX(),0,-mMaxLength,0,200);
invalidate();
mDeleteBtnState = 0;
return false;
}else{
return false;
}
break;
case MotionEvent.ACTION_MOVE:
if(!isSupportRemove()){
return super.onTouchEvent(e);
}
int dx = mLastX - x;
int dy = mLastY - y;
int scrollX = mItemLayout.getScrollX();
if(Math.abs(dx) >Math.abs(dy)){
isItemMoving = true;
if(scrollX + dx <= 0){
mItemLayout.scrollTo(0,0);
return true;
}else if(scrollX + dx >= mMaxLength){
mItemLayout.scrollTo(mMaxLength,0);
return true;
}
mItemLayout.scrollBy(dx,0);
}
break;
case MotionEvent.ACTION_UP:
if(!isSupportRemove()){
retrun super.onTouchEvent(e);
}
if(!isItemMoving && !isDragging && mListener!= null){
mListener.onItemClick(mItemLayout,mPosition);
}
isItemMoving = false;
mVelocityTracker.computeCurrentVelocity(1000);//计算手指滑动速度
float xVelocity = mVelocityTracker.getXVelocity();//向左滑动为负
float yVelocity = mVelocityTracker.getYVelocity();
int deltaX = 0;
int upScrollX = mItemLayout.getScrollX();
if(Math.abs(xVelocity) >100 && Math.abs(xVelocity) > Math.abs(yVelocity)){
if(xVelocity <= -100){
deltaX = mMaxLength - upScrollX;
mDeleteBtnState = 2;
}else if(xVelocity > 100){
deltaX = -upScrollX;
mDeleteBtnState = 1;
}
}else{
if(upScrollX >= mMaxLength / 2){
deltaX = mMaxLength - upScrollX;
mDeleteBtnState = 1;
}
}else{
if(upScrollX >= mMaxLength/2){
deltaX = mMaxLength - upScrollX;
mDeleteBtnState = 2;
} else if(upScrollX < mMaxLength /2 ){
deltaX = -upScrollX;
mDeleteBtnState = 1;
}
}
mScroller.startScroll(upScrollX,0,deltaX,0,200);
isStartScroll = true;
invalidate();
mVelocityTracker.clear();
break;
}
mLastX = x;
mLastY = y;
return super.onTouchEvent(e);
}
@Override
public void computeScroll(){
if(mScroller.computeScrollOffset()){
mItemLayout.scrollerTo(mScroller.getCurrX(),mScroller.getCurrY());
invalidate();
}else if(isStartScroll){
isStartScroll = false;
if(mDeleteBtnState == 1) {
mDeleteBtnState = 0;
}
if(mDeleteBtnState == 2){
mDeleteBtnState = 3;
}
}
}
@Override
protected void onDetachedFromWindow(){
mVelocityTracker.recycle();
super.onDetachedFromWindow();
}
@Override
public void onScrollStateChanged(int state){
super.onScrollStateChanged(state);
isDragging = state == SCROLL_STATE_DRAGGING;
}
public void setOnItemClickListener(OnItemClickListenr listener){mListener = listener;)
public boolean isSupportRemove() {return isSupportRemove;}
public void setSupportRemove(boolean supportRemove){isSupportRemove = supportRemove;}
}