最近项目中需要实现银行卡侧滑删除以及选择默认无法删除的效果,需求效果图如下:
其实就是一个自定义的列表实现,这里我用的是recyclerView首先需要自定义DeleteBankRecyclerView继承RecyclerView,需要注意的是item的点击和滑动事件的处理。
代码如下:
@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 (status == CLOSE) {
//寻找对应坐标点下的V
View view = findChildViewUnder(x, y);
if (view == null) {
return false;
}
//通过BankMsgViewHolder获取对应的子View,详情可以看代码
BankMsgListAdapter.BankMsgViewHolder viewHolder = (BankMsgListAdapter.BankMsgViewHolder) getChildViewHolder(view);
mItemView = viewHolder.itemView.findViewById(R.id.item_layout);
rlBankMsg = (RelativeLayout) viewHolder.itemView.findViewById(R.id.rl_bank_msg);//item的内容
ivDefaultIcon = (ImageView) viewHolder.itemView.findViewById(R.id.iv_default_icon);//默认选择框
mPosition = viewHolder.getAdapterPosition();
mDeleteView = (TextView) viewHolder.itemView.findViewById(R.id.item_delete);
if(isForbidSideSlip){
mDeleteView.setVisibility(GONE);
}
mMaxLength = mDeleteView.getWidth();
mDeleteView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
//返回原点
mItemView.scrollTo(0,0);
status = CLOSE;
if (mListener!=null)
mListener.onDeleteClick(mPosition);
}
});
//当删除图片已经完全显示的时候
}else if (status == OPEN){
//从当前view的偏移点mItemView.getScrollX(),位移-mMaxLength长度单位
// 时间DEFAULT_TIMEms,向左移动为正数
mScroller.startScroll(mItemView.getScrollX(),0,-mMaxLength,0,DEFAULT_TIME);
//刷新下一帧动画
invalidate();
status = CLOSE;
return false;
}else {
return false;
}
break;
case MotionEvent.ACTION_MOVE:
//获取上次的落点与当前的坐标之间的差值
int dx = mLastX - x;
int dy = mLastY - y;
int scrollX = mItemView.getScrollX();
//水平滑动距离大于垂直距离
if (Math.abs(dx)>Math.abs(dy) && !isForbidSideSlip){
isHorMoving = true;
//向左滑动,直至显示删除按钮,向左滑动的最大距离不超过删除按钮的宽度
if (scrollX+dx>=mMaxLength){
mItemView.scrollTo(mMaxLength,0);
return true;
//向右滑动,直至删除按钮不显示,向右滑动的最大距离不超过初始位置
}else if (scrollX+dx<=0){
mItemView.scrollTo(0,0);
return true;
}
//如果在图片还未完全显示的状态下,那么手指滑动多少,图片就移动多少
mItemView.scrollBy(dx,0);
//mItemView.scrollTo(dx+scrollX,0);
}
break;
case MotionEvent.ACTION_UP:
if (!isHorMoving && !isVerMoving && mListener!=null){
mListener.onItemClick(mItemView,ivDefaultIcon,mPosition);
}
isHorMoving = false;
mVelocityTracker.computeCurrentVelocity(1000);//计算手指滑动的速度
float xVelocity = mVelocityTracker.getXVelocity();//水平方向速度(向左为负)
float yVelocity = mVelocityTracker.getYVelocity();//垂直方向速度
int upScrollX = mItemView.getScrollX();
int deltaX = 0 ;
//向右滑动速度为正数
//滑动速度快的状态下抬起手指,计算所需偏移量
if (Math.abs(xVelocity)>Math.abs(yVelocity) && Math.abs(xVelocity)>=VELOCITY && !isForbidSideSlip){
//向右隐藏
if (xVelocity >= VELOCITY){
deltaX = -upScrollX;
status = CLOSING;
}else if (xVelocity <= -VELOCITY){
deltaX = mMaxLength - upScrollX;
status = OPENING;
}
//滑动速度慢的状态下抬起手指,如果滑动距离大于1/2的图片宽度,计算偏移量
//不够的话恢复原点
}else {
if(!isForbidSideSlip){
if (upScrollX >= mMaxLength/2){
deltaX = mMaxLength - upScrollX;
status = OPENING;
}else {
deltaX = -upScrollX;
status = CLOSING;
}
}
}
mScroller.startScroll(upScrollX,0,deltaX,0,DEFAULT_TIME);
isStartScroll = true;
invalidate();
mVelocityTracker.clear();
break;
}
mLastX = x;
mLastY = y;
return super.onTouchEvent(e);
}
@Override
public void computeScroll() {
//滚动是否完成,true表示还未完成
if (mScroller.computeScrollOffset()){
mItemView.scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
invalidate();
//有滑动,并且在滑动结束的时候
}else if (isStartScroll){
isStartScroll = false;
if (status == CLOSING)
status = CLOSE;
if (status == OPENING)
status = OPEN;
}
}
@Override
protected void onDetachedFromWindow() {
mVelocityTracker.recycle();
super.onDetachedFromWindow();
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
isVerMoving = state == SCROLL_STATE_DRAGGING;
}
//禁止侧滑
public void forbidSideSlip(){
this.isForbidSideSlip = true;
}
// public void setOnItemClickListener(OnItemClickListener listener){
// this.mListener = listener;
// }
public void setOnItemClickListener(OnItemClickListener listener){
this.mListener = listener;
}
public interface OnItemClickListener {
/**
* item点击回调
*
* @param view
* @param position
*/
void onItemClick(View view,ImageView imageView, int position);
/**
* 删除按钮回调
*
* @param position
*/
void onDeleteClick(int position);
}
需要说明的是 OnItemClickListener 下面的两个方法是自定义的,为了方便对item的事件处理。
自定义view之后,就是布局当中的应用,代码如下:
除了主布局还需要一个adapter,去展示item的具体布局如下:
public class BankMsgListAdapter extends RecyclerView.Adapter {
private Context mContext;
private LayoutInflater mInflater;
private List mList;//BankCardListBean可以根据自己要求设置
private String num;
private boolean isOnlySelectBankCard;
public BankMsgListAdapter(Context context, List list,boolean isOnlySelectBankCard) {
mContext = context;
mInflater = LayoutInflater.from(context);
mList = list;
this.isOnlySelectBankCard = isOnlySelectBankCard;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new BankMsgViewHolder(mInflater.inflate(R.layout.adapter_bank_msg_list_item,parent,false));
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if(holder instanceof BankMsgViewHolder){
BankCardListBean bankCardListBean = mList.get(position);
String bankCode = bankCardListBean.getcBankCode();
if(!StringUtils.isEmpty(bankCode)){
int drawable = BankUtil.logoForBankCode(bankCode);
if (drawable != 0) {
((BankMsgViewHolder) holder).ivBankIcon.setImageResource(drawable);
}
}
String cardNo = bankCardListBean.getcCardNo();
if (!StringUtils.isEmpty(cardNo) && cardNo.length()>4){
num = cardNo.substring(cardNo.length()-4,cardNo.length());
}
String bankName = bankCardListBean.getcBankName();
if (!StringUtils.isEmpty(bankName)){
((BankMsgViewHolder)holder).tvBankName.setText(bankName + "("+ num +")");
}
if(isOnlySelectBankCard){
((BankMsgViewHolder)holder).ivDefaultIcon.setVisibility(View.GONE);
((BankMsgViewHolder)holder).tvWordDefault.setVisibility(View.GONE);
}else {
((BankMsgViewHolder)holder).ivDefaultIcon.setVisibility(View.VISIBLE);
((BankMsgViewHolder)holder).tvWordDefault.setVisibility(View.VISIBLE);
Boolean aDefault = bankCardListBean.getnDefault();
if (aDefault){
((BankMsgViewHolder)holder).ivDefaultIcon.setImageResource(R.drawable.yixuan);
}else {
((BankMsgViewHolder)holder).ivDefaultIcon.setImageResource(R.drawable.weixuan);
}
}
}
}
@Override
public int getItemCount() {
return mList != null ? mList.size() : 0;
}
public class BankMsgViewHolder extends RecyclerView.ViewHolder {
private final TextView itemDelete;//删除按钮
private final ImageView ivBankIcon;//银行图标
private final TextView tvBankName;//银行名称
private final ImageView ivDefaultIcon;//默认图标
private final RelativeLayout rlBankMsg;//item的内容布局
private final TextView tvWordDefault;
public BankMsgViewHolder(View inflate) {
super(inflate);
rlBankMsg = (RelativeLayout) inflate.findViewById(R.id.rl_bank_msg);
tvBankName = (TextView) inflate.findViewById(R.id.tv_bank_name);
ivBankIcon = (ImageView) inflate.findViewById(R.id.iv_bank_icon);
ivDefaultIcon = (ImageView) inflate.findViewById(R.id.iv_default_icon);
itemDelete = (TextView) inflate.findViewById(R.id.item_delete);
tvWordDefault = (TextView) inflate.findViewById(R.id.tv_word_default);
itemView.setTag(this);
}
}
public void removeItem(int position) {
mList.remove(position);
notifyItemRemoved(position);
}
}
item的具体布局:
然后初始化布局,实现相应的方法如下:
rc_bank_list.setOnItemClickListener(new DeleteBankRecyclerView.OnItemClickListener() {
@Override
public void onItemClick(View view, ImageView imageView, int position) {
// 点击操作
}
@Override
public void onDeleteClick(int position) {
//点击删除操作,调用删除方法或接口
}
});
以上是实现具体功能的主要代码块,希望可以给需要的你提供一点点帮助!