滑动删除条目控件的简易实现

工作中有时候会碰到需要列表侧滑删除的功能,在网上找了很多都需要定制listview列子,这在有些情况下会不太适合需求,所以我这里实现了一种值需要在列表中的item中使用这个控件的做法,与列表控件的自定义程度无关。,大家可以按照需求借鉴一下

惯例上图(注:侧滑有回弹效果哦):

    

 

 

public class MyScrollDeleteView extends ViewGroup {
    private final Scroller scroller;
    private final int slop;
    private int leftBorder;
    private int rightBorder;
    private float mXDown;
    private float mXLastMove;
    private float mXMove;

    public MyScrollDeleteView(Context context) {
        this(context, null);
    }

    public MyScrollDeleteView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyScrollDeleteView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        scroller = new Scroller(context);
        slop = ViewConfigurationCompat.getScaledPagingTouchSlop(ViewConfiguration.get(context));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
        }
        measureChild(getChildAt(0), widthMeasureSpec, heightMeasureSpec);
        measureChild(getChildAt(1), widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        if (changed) {
            for (int i = 0; i < childCount; i++) {
                View childView = getChildAt(i);
                getChildAt(0).layout(0, 0, getChildAt(0).getMeasuredWidth(), getChildAt(0).getMeasuredHeight());
                getChildAt(1).layout(getChildAt(0).getMeasuredWidth(), 0, getChildAt(0).getMeasuredWidth() + getChildAt(1).getMeasuredWidth(), getChildAt(1).getMeasuredHeight());
                leftBorder = getChildAt(0).getLeft();
                rightBorder = getChildAt(childCount - 1).getRight();
//                Toast.makeText(getContext(), leftBorder + "---" + rightBorder, Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mXDown = ev.getRawX();
                mXLastMove = mXDown;
                break;
            case MotionEvent.ACTION_MOVE:
                mXMove = ev.getRawX();
                float diff = Math.abs(mXMove - mXDown);
                mXLastMove = mXMove;
                //当手指拖动值大于TouchSlop值时,认为应该进行滚动,拦截子控件的事件 
                if (diff > slop) {
                return true;
            }
                break;
        } return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                return true;
            case MotionEvent.ACTION_MOVE:
                mXMove = event.getRawX();
                int scrolledX = (int) (mXLastMove - mXMove);
                if (getScrollX() + scrolledX < leftBorder) {
                    scrollTo(leftBorder, 0);
                    return true;
                } else if (getScrollX() + getWidth() + scrolledX > rightBorder) {
                    scrollTo(rightBorder - getWidth(), 0);
                    return true;
                }
                scrollBy(scrolledX, 0);
                mXLastMove = mXMove;
                break;
            case MotionEvent.ACTION_UP:
                //当手指抬起时,根据当前的滚动值来判定应该滚动到哪个子控件的界面
                int targetIndex = (getScrollX() + getChildAt(1).getMeasuredWidth() / 2) / getChildAt(1).getMeasuredWidth();
                int dx = targetIndex * getChildAt(1).getMeasuredWidth() - getScrollX();
                //第二步,调用startScroll() 方法来初始化滚动数据并刷新界面 
                scroller.startScroll(getScrollX(), 0, dx, 0);
                invalidate();
                break;
        } return super.onTouchEvent(event);
    } /*如果是列表项,可以使用这个方法做初始化,delete按钮的视图重复,用法:在列表的adapter中做初始化*/

    public void setScrollInit() {
        scroller.startScroll(0, 0, 0, 0);
        invalidate();
    }

    @Override
    public void computeScroll() {
        if (scroller.computeScrollOffset()) {
            //这里调用View的scrollTo() 完成实际的滚动
            scrollTo (scroller.getCurrX(), scroller.getCurrY());
            //必须调用该方法,否则不一定能看到滚动效果
            invalidate ();
        } super.computeScroll();
    }
} 

适配器Adapter代码:

 

private class MyAdapter extends BaseAdapter {

    private Context context;
    private List<String> dats;

    public MyAdapter(Context context, List<String> dats) {
        this.context = context;
        this.dats = dats;
    }

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

    @Override
    public Object getItem(int i) {
        return dats.get(i);
    }

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

    @Override
    public View getView(final int i, View view, ViewGroup viewGroup) {
        MyHolder holder=null;
        if(view==null){
        holder=new MyHolder();
            view=View.inflate(context,R.layout.lv_item,null);
            holder.tv_name=view.findViewById(R.id.tv_name);
            holder.delete=view.findViewById(R.id.delete);
            holder.item_parent=(MyScrollDeleteView)view.findViewById(R.id.item_parent);
            view.setTag(holder);
        }else{
            holder= (MyHolder) view.getTag();
        }
        holder.item_parent.setScrollInit();
        holder.tv_name.setText(mdatas.get(i));
        holder.delete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context,"hehe",Toast.LENGTH_SHORT).show();
                delete(i);
            }
        });
        holder.tv_name.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context,"xixi",Toast.LENGTH_SHORT).show();
            }
        });
        return view;
    }

    public void delete(int pos){
        dats.remove(pos);
        notifyDataSetChanged();
    }
}

private class MyHolder{
    public TextView tv_name;
    public TextView delete;
    public MyScrollDeleteView item_parent;
}

 

 

 

子条目的布局代码:(建议大家在布局中指定MyScrollDeletview的高度,dp单位不影响适配)

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.xuganwen.testui.MyScrollDeleteView
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:id="@+id/item_parent"
        >
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/tv_name"
            android:background="@android:color/holo_blue_bright"
            />
        <TextView
            android:layout_width="100dp"
            android:layout_height="match_parent"
            android:id="@+id/delete"
            android:background="#6F00"
            android:text="delete"/>
    </com.xuganwen.testui.MyScrollDeleteView>
</LinearLayout>

 

//当使用列表listview时,需要避免滑动冲突,我这里使用的listview代码如下:就是根据滑动方向和距离的大小来判断到底是由listview还是由子条目来处理事件:

 

 

package com.hs.qianshubao.wealth.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ListView;

/**
 * Created by aa on 2016/3/23.
 */
public class MyListview extends ListView {

    public MyListview(Context context){
        this(context,null);
    }

    public MyListview(Context context, AttributeSet attributeSet){
        super(context,attributeSet);
    }
    public MyListview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int height=MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, height);
    }
    private boolean flag=false;
    private float downX=0;
    private float downY=0;
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                downX=ev.getX();
                downY=ev.getY();

                //初始化  表明每次都是开始点击该控件
                flag=false;
                break;
            case MotionEvent.ACTION_MOVE:
                float x=ev.getX()-downX;
                float y=ev.getY()-downY;

                if(Math.abs(x)> Math.abs(y)){
                    flag=false;
                }else{
                    flag=true;
                }
//                getParent().requestDisallowInterceptTouchEvent(!flag);
                requestDisallowInterceptTouchEvent(!flag);
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}

 

 

 

 

这只是一个简单的滚动效果,增加一下自己的技术栈,欢迎褒贬。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值