您的位置:首页 > 其它

高仿QQ侧滑item删除的自定义ListView

2017-04-28 14:47 281 查看
预览效果GIF图:



带注释源码:

注释中已将实现步骤写好,欢迎留言交流,运行Mode地址:https://github.com/jiarWang/AndroidView/tree/master/SlideListView_4_28

public class SlideListView extends ListView {

private final int CONTENT_POSITION = 0;
private final int DELETE_POSITION = 1;

private int mScreenWidth;   //屏幕宽度
private int deleteWidth;
private ViewGroup targetItemViewGroup;  //被标记item
private boolean isSelect;   //是否有选中,标记

private int downX;  //DOWN时的X
private int downY;
private LinearLayout.LayoutParams childOneParams;   //padding操作的child数据

public SlideListView(Context context) {
super(context, null);
init(context);
}

public SlideListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

public SlideListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

public SlideListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}

private void init(Context context) {

WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(displayMetrics);
mScreenWidth = displayMetrics.widthPixels;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
return performActionAsDown(ev);
case MotionEvent.ACTION_MOVE:
performActionAsMove(ev);
break;
case MotionEvent.ACTION_UP:
performActionAsUp(ev);
break;
}

return super.onTouchEvent(ev);
}
/**
* 1、获取屏幕宽度,绘制当前的子item,使其保持DOWN前的状态
* 2、判断是否有item已经被选中标记(有Delete控件);
*          如果已经有被标记item,判断被标记item是否为当前点击处对应的item?
*              是:则此时不做处理,
*              否:则还原被标记item,拦截事件
*          如果没有,则将当前DOWN处的作为标记item
* */
private boolean performActionAsDown(MotionEvent ev) {

downX = (int)ev.getX();
downY
4000
= (int)ev.getY();

ViewGroup tmpItem = (ViewGroup) this.getChildAt(pointToPosition(downX, downY) - getFirstVisiblePosition());
if (isSelect){
if (tmpItem != targetItemViewGroup){
turnToNormal();
return false;
}
}else{
targetItemViewGroup = tmpItem;
childOneParams = (LinearLayout.LayoutParams) targetItemViewGroup.getChildAt(CONTENT_POSITION).getLayoutParams();
childOneParams.width = mScreenWidth;
targetItemViewGroup.getChildAt(CONTENT_POSITION).setLayoutParams(childOneParams);
deleteWidth = targetItemViewGroup.getChildAt(DELETE_POSITION).getLayoutParams().width;
}
return true;
}
/**
* 重置选中item视图,标记判断置位false,选中item置为null
* */
public void turnToNormal() {
if (targetItemViewGroup != null){
childOneParams.leftMargin = 0;
targetItemViewGroup.getChildAt(CONTENT_POSITION).setLayoutParams(childOneParams);
isSelect = false;
}
}

/**通过performActionAsDown后,只有被标记item才有MOVE响应
* 判断是否有item已经被选中标记(有Delete控件);
*          是:判断手势-->向左不处理,向右则修改Child的padding,不得超过padding界线
*          否:判断手势-->向右不处理,向左则修改Child的padding,不得超过padding界线
* */
private void performActionAsMove(MotionEvent ev) {
if (targetItemViewGroup == null) return;
int moveX = (int) ev.getX();
int moveY = (int)ev.getY();

int diffX = moveX - downX;
int diffY = moveY - downY;

if (isSelect){
if (diffX > 0  && Math.abs(diffX) > Math.abs(diffY)){   //右滑
if (diffX > deleteWidth){
diffX = deleteWidth;
}
childOneParams.leftMargin = diffX - deleteWidth;
}
}else {
if (diffX < 0 && Math.abs(diffX) > Math.abs(diffY)){
if (Math.abs(diffX) > deleteWidth){
diffX = -deleteWidth;
}
childOneParams.leftMargin = diffX;
}
}
targetItemViewGroup.getChildAt(CONTENT_POSITION).setLayoutParams(childOneParams);
}
/**
* 判断是否有选中标记位?
*      有:标记item的Delete控件全显示,设置标志位
*      无:则标记item至为normal,设置标志位
* */
private void performActionAsUp(MotionEvent ev) {
int upX = (int) ev.getX();
int upY = (int)ev.getY();

int diffX = upX - downX;
int diffY = upY - downY;
if (! isSelect && diffX < 0 && Math.abs(diffX) > Math.abs(diffY)){
isSelect = true;
childOneParams.leftMargin = - deleteWidth;
}else if (isSelect && diffX > 0 && Math.abs(diffX) > Math.abs(diffY)){
childOneParams.leftMargin = 0;
isSelect = false;
}
targetItemViewGroup.getChildAt(CONTENT_POSITION).setLayoutParams(childOneParams);
}
}


自定义SlideAdapter源码:

adapter源码比较简单,只是需要说明的是,要将SlideListView对象传递进来,在执行删除操作时需要。

public class SlideAdapter extends BaseAdapter {

private List<String> list = new ArrayList<>();
private LayoutInflater inflater;
private SlideListView listView;

SlideAdapter(Context context, List<String> data, SlideListView listView){
list.clear();
list.addAll(data);
inflater = LayoutInflater.from(context);
this.listView = listView;
}

@Override
public int getCount() {
return list.size();
}

@Override
public Object getItem(int position) {
return list.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
Holder holder = null;
if (convertView == null) {

convertView = inflater.inflate(R.layout.slide_item, parent, false);

holder = new Holder();
holder.tv_content = (TextView) convertView.findViewById(R.id.tv_content);
holder.tv_delete = (TextView) convertView.findViewById(R.id.tv_delete);

convertView.setTag(holder);
}else {
holder = (Holder) convertView.getTag();
}

holder.tv_content.setText(getItem(position).toString());
holder.tv_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
list.remove(position);
listView.turnToNormal();
notifyDataSetChanged();
}
});
return convertView;
}

class Holder{
TextView tv_content;
TextView tv_delete;
}
}
实例化及适配器的使用:

slideListView = (SlideListView) findViewById(R.id.slideView);
slideAdapter = new SlideAdapter(this, data, slideListView);
slideListView.setAdapter(slideAdapter);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: