Android类似QQ左划出现删除按钮点击效果的ListView

当下对listview的item进行左划的操作,实现删除按钮的划出并且点击删除的功能是比较流行的。在开发的过程中,本人也使用到了这部分的内容,写一些自己的心得,希望能对大家有所帮助。

实现的效果图如下(只是截图了一部分):


首先,我们先自定义一个SwipeListView的Listview的类,这个类在我们的布局文件的引用中要用到。

废话不多说,SwipeListView.class代码如下,可以直接复用:

import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.ListView;

public class SwipeListView extends ListView {
   
   private static final int TOUCH_STATE_NONE = 0;
   private static final int TOUCH_STATE_X = 1;
   private static final int TOUCH_STATE_Y = 2;

   private int MAX_Y = 5;
   private int MAX_X = 3;
   private float mDownX;
   private float mDownY;
   private int mTouchState;
   private int mTouchPosition;
   private SwipeItemLayout mTouchView;
   private Interpolator mCloseInterpolator;
   private Interpolator mOpenInterpolator;

   public SwipeListView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      // TODO Auto-generated constructor stub
      init();
   }

   public SwipeListView(Context context, AttributeSet attrs) {
      super(context, attrs);
      // TODO Auto-generated constructor stub
      init();
   }

   public SwipeListView(Context context) {
      super(context);
      // TODO Auto-generated constructor stub
      init();
   }

   private void init() {
      MAX_X = dp2px(MAX_X);
      MAX_Y = dp2px(MAX_Y);
      mTouchState = TOUCH_STATE_NONE;
   }

   public void setCloseInterpolator(Interpolator interpolator) {
      mCloseInterpolator = interpolator;
   }

   public void setOpenInterpolator(Interpolator interpolator) {
      mOpenInterpolator = interpolator;
   }

   public Interpolator getOpenInterpolator() {
      return mOpenInterpolator;
   }

   public Interpolator getCloseInterpolator() {
      return mCloseInterpolator;
   }

   @Override
   public boolean onInterceptTouchEvent(MotionEvent ev) {
      return super.onInterceptTouchEvent(ev);
   }

   @Override
   public boolean onTouchEvent(MotionEvent ev) {
      if (ev.getAction() != MotionEvent.ACTION_DOWN && mTouchView == null)
         return super.onTouchEvent(ev);
      int action = MotionEventCompat.getActionMasked(ev);
      action = ev.getAction();
      switch (action) {
      case MotionEvent.ACTION_DOWN:
         int oldPos = mTouchPosition;
         mDownX = ev.getX();
         mDownY = ev.getY();
         mTouchState = TOUCH_STATE_NONE;

         mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY());

         if (mTouchPosition == oldPos && mTouchView != null
               && mTouchView.isOpen()) {
            mTouchState = TOUCH_STATE_X;
            mTouchView.onSwipe(ev);
            return true;
         }

         View view = getChildAt(mTouchPosition - getFirstVisiblePosition());

         if (mTouchView != null && mTouchView.isOpen()) {
            mTouchView.smoothCloseMenu();
            mTouchView = null;
            return super.onTouchEvent(ev);
         }
         if (view instanceof SwipeItemLayout) {
            mTouchView = (SwipeItemLayout) view;
         }
         if (mTouchView != null) {
            mTouchView.onSwipe(ev);
         }
         break;
      case MotionEvent.ACTION_MOVE:
         float dy = Math.abs((ev.getY() - mDownY));
         float dx = Math.abs((ev.getX() - mDownX));
         if (mTouchState == TOUCH_STATE_X) {
            if (mTouchView != null) {
               mTouchView.onSwipe(ev);
            }
            getSelector().setState(new int[] { 0 });
            ev.setAction(MotionEvent.ACTION_CANCEL);
            super.onTouchEvent(ev);
            return true;
         } else if (mTouchState == TOUCH_STATE_NONE) {
            if (Math.abs(dy) > MAX_Y) {
               mTouchState = TOUCH_STATE_Y;
            } else if (dx > MAX_X) {
               mTouchState = TOUCH_STATE_X;
            }
         }
         break;
      case MotionEvent.ACTION_UP:
         if (mTouchState == TOUCH_STATE_X) {
            if (mTouchView != null) {
               mTouchView.onSwipe(ev);
               if (!mTouchView.isOpen()) {
                  mTouchPosition = -1;
                  mTouchView = null;
               }
            }
            ev.setAction(MotionEvent.ACTION_CANCEL);
            super.onTouchEvent(ev);
            return true;
         }
         break;
      }
      return super.onTouchEvent(ev);
   }

   public void smoothOpenMenu(int position) {
      if (position >= getFirstVisiblePosition()
            && position <= getLastVisiblePosition()) {
         View view = getChildAt(position - getFirstVisiblePosition());
         if (view instanceof SwipeItemLayout) {
            mTouchPosition = position;
            if (mTouchView != null && mTouchView.isOpen()) {
               mTouchView.smoothCloseMenu();
            }
            mTouchView = (SwipeItemLayout) view;
            mTouchView.smoothOpenMenu();
         }
      }
   }

   private int dp2px(int dp) {
      return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
            getContext().getResources().getDisplayMetrics());
   }
}


然后要定义我们的item项,SwipItemLayout.class的代码如下:

import android.support.v4.widget.ScrollerCompat;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
import android.widget.FrameLayout;


public class SwipeItemLayout extends FrameLayout {
   private View contentView = null;
   private View menuView = null;
   private Interpolator closeInterpolator = null;
   private Interpolator openInterpolator = null;
   
   private ScrollerCompat mOpenScroller;
   private ScrollerCompat mCloseScroller;
   
   private int mBaseX;
   private int mDownX;
   private int state = STATE_CLOSE;
   
   private static final int STATE_CLOSE = 0;
   private static final int STATE_OPEN = 1;
   
   public SwipeItemLayout(View contentView,View menuView,Interpolator closeInterpolator, Interpolator openInterpolator){
      super(contentView.getContext());
      this.contentView = contentView;
      this.menuView = menuView;
      this.closeInterpolator = closeInterpolator;
      this.openInterpolator = openInterpolator;
      
      init();
   }
   
   private void init(){
      setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
            LayoutParams.WRAP_CONTENT));

      if (closeInterpolator != null) {
         mCloseScroller = ScrollerCompat.create(getContext(),
               closeInterpolator);
      } else {
         mCloseScroller = ScrollerCompat.create(getContext());
      }
      if (openInterpolator != null) {
         mOpenScroller = ScrollerCompat.create(getContext(),
               openInterpolator);
      } else {
         mOpenScroller = ScrollerCompat.create(getContext());
      }
      
      LayoutParams contentParams = new LayoutParams(
            LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
      contentView.setLayoutParams(contentParams);

      menuView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
            LayoutParams.WRAP_CONTENT));

      addView(contentView);
      addView(menuView);
   }
   
   public boolean onSwipe(MotionEvent event) {
      switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
         mDownX = (int) event.getX();
         break;
      case MotionEvent.ACTION_MOVE:
         // Log.i("byz", "downX = " + mDownX + ", moveX = " + event.getX());
         int dis = (int) (mDownX - event.getX());
         if (state == STATE_OPEN) {
            dis += menuView.getWidth();
         }
         swipe(dis);
         break;
      case MotionEvent.ACTION_UP:
         if ((mDownX - event.getX()) > (menuView.getWidth() / 2)) {
            // open
            smoothOpenMenu();
         } else {
            // close
            smoothCloseMenu();
            return false;
         }
         break;
      }
      return true;
   }
   
   public boolean isOpen() {
      return state == STATE_OPEN;
   }
   
   private void swipe(int dis) {
      if (dis > menuView.getWidth()) {
         dis = menuView.getWidth();
      }
      if (dis < 0) {
         dis = 0;
      }
      contentView.layout(-dis, contentView.getTop(),
            contentView.getWidth() - dis, getMeasuredHeight());
      menuView.layout(contentView.getWidth() - dis, menuView.getTop(),
            contentView.getWidth() + menuView.getWidth() - dis,
            menuView.getBottom());
   }
   
   @Override
   public void computeScroll() {
      if (state == STATE_OPEN) {
         if (mOpenScroller.computeScrollOffset()) {
            swipe(mOpenScroller.getCurrX());
            postInvalidate();
         }
      } else {
         if (mCloseScroller.computeScrollOffset()) {
            swipe(mBaseX - mCloseScroller.getCurrX());
            postInvalidate();
         }
      }
   }
   
   public void smoothCloseMenu() {
      state = STATE_CLOSE;
      mBaseX = -contentView.getLeft();
      System.out.println(mBaseX);
      mCloseScroller.startScroll(0, 0, mBaseX, 0, 350);
      postInvalidate();
   }
   
   public void smoothOpenMenu() {
      state = STATE_OPEN;
      mOpenScroller.startScroll(-contentView.getLeft(), 0,
            menuView.getWidth(), 0, 350);
      postInvalidate();
   }
   public void closeMenu() {
      if (mCloseScroller.computeScrollOffset()) {
         mCloseScroller.abortAnimation();
      }
      if (state == STATE_OPEN) {
         state = STATE_CLOSE;
         swipe(0);
      }
   }

   public void openMenu() {
      if (state == STATE_CLOSE) {
         state = STATE_OPEN;
         swipe(menuView.getWidth());
      }
   }

   public View getContentView() {
      return contentView;
   }

   public View getMenuView() {
      return menuView;
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      menuView.measure(MeasureSpec.makeMeasureSpec(0,
            MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(
            getMeasuredHeight(), MeasureSpec.EXACTLY));
   }

   @Override
   protected void onLayout(boolean changed, int l, int t, int r, int b) {
      contentView.layout(0, 0, getMeasuredWidth(),
            contentView.getMeasuredHeight());
      menuView.layout(getMeasuredWidth(), 0,
            getMeasuredWidth() + menuView.getMeasuredWidth(),
            contentView.getMeasuredHeight());
      // setMenuHeight(mContentView.getMeasuredHeight());
      // bringChildToFront(mContentView);
   }
}

而我们要出现的左划删除的按钮效果,是在listview中的,需要定义我们listview的适配器,我们适配器SwipeAdapter的代码如下:

public class SwipeAdapter extends BaseAdapter {
    private Context mContext = null;
    private List<Map<String, Object>> listItems;    //评论回复集合

    public SwipeAdapter(Context context, List<Map<String, Object>> listItems) {
        this.mContext = context;
        this.listItems = listItems;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return listItems.size();
    }

    @Override
    public Object getItem(int arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int arg0) {
        // TODO Auto-generated method stub
        return arg0;
    }

    @Override
    public View getView(int position, View contentView, ViewGroup arg2) {
        ViewHolder holder = null;
        if (contentView == null) {
            holder = new ViewHolder();
            View view01 = LayoutInflater.from(mContext).inflate(R.layout.list_message_item, null);
            View view02 = LayoutInflater.from(mContext).inflate(R.layout.btn_delete, null);
            holder.btn = (Button) view02.findViewById(R.id.btn_delete);
            holder.img_icon = (ImageView) view01.findViewById(R.id.img_icon);
            holder.text_type = (TextView) view01.findViewById(R.id.text_type);
            holder.text_title = (TextView) view01.findViewById(R.id.text_title);
            holder.text_time = (TextView) view01.findViewById(R.id.text_time);
            holder.text_content = (TextView) view01.findViewById(R.id.text_content);
            contentView = new SwipeItemLayout(view01, view02, null, null);
            contentView.setTag(holder);
        } else {
            holder = (ViewHolder) contentView.getTag();
        }

        holder.btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                Toast.makeText(mContext, "click", Toast.LENGTH_LONG).show();
            }
        });
        holder.text_title.setText((String) listItems.get(position).get("title"));
        return contentView;
    }

    class ViewHolder {
        public Button btn;
        public ImageView img_icon;
        public TextView text_type, text_title, text_time, text_content;
    }
}
adapter的编写还是比较简单的,大家主要看一下viewHolder的容器和getViewa()就Ok啦。然后说一下view01和view02中用到的两个layout,分别代表我们的一个item的layout和删除按钮的layout。

然后item的layout和删除按钮的layout的xml分别如下:

item的xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#353535"
    android:orientation="horizontal">

    <RelativeLayout
        android:id="@+id/rela_list_message"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:background="#4c4c4c">

        <RelativeLayout
            android:id="@+id/rela_msg_left"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="15dp">

            <com.kegoal.view.CircleImageView
                android:id="@+id/img_msg_icon"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:src="@mipmap/ic_launcher" />

            <TextView
                android:id="@+id/text_type"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@id/img_msg_icon"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="3dp"
                android:text="文本测试"
                android:textColor="#de6654"
                android:textSize="9sp" />
        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/rela_msg_center"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="31dp"
            android:layout_toRightOf="@id/rela_msg_left">

            <RelativeLayout
                android:id="@+id/rela_msg_right_top"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/text_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="反馈"
                    android:textColor="#cccccc"
                    android:textSize="15sp" />

                <TextView
                    android:id="@+id/text_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentRight="true"
                    android:text="2016.05.01 08:00"
                    android:textColor="#8e8e8e"
                    android:textSize="12sp" />
            </RelativeLayout>

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@id/rela_msg_right_top"
                android:layout_marginTop="4dp">

                <TextView
                    android:id="@+id/text_content"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="发的撒可减肥大赛非打死你非大放送"
                    android:textColor="#8e8e8e"
                    android:textSize="14sp" />
            </RelativeLayout>

        </RelativeLayout>

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerInParent="true"
            android:layout_marginRight="13dp">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@mipmap/icon_right" />
        </RelativeLayout>
    </RelativeLayout>
</RelativeLayout>
删除按钮的xml的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#de6654"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_delete"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="#de6654"
        android:text="删除"
        android:textColor="#ffffff" />
</LinearLayout>
这些准备完事以后,就是最后的调用的一步了,在我们需要用到这个左划删除的activity中,声明以下,然后setAdapter等操作即可完成我们的界面,具体代码如下:

声明部分:

private SwipeListView lv_message = null;
private List<Map<String, Object>> listItems;
onCreate()部分:

/**
 * listview的处理适配
 * */
lv_message = (SwipeListView) findViewById(R.id.lv_message);
listItems = getListItems();
SwipeAdapter adapter = new SwipeAdapter(this, listItems);
lv_message.setAdapter(adapter);
然后getListItems()的代码:

 /**
     * 初始化item信息
     */
    private List<Map<String, Object>> getListItems() {
        List<Map<String, Object>> listItems = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < 5; i++) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("", "");
//            map.put("image", imgeIDs[i]);               //图片资源
            map.put("title", "大大" + i);              //title
//            map.put("info", goodsNames[i]);     //物品名称
//            map.put("detail", goodsDetails[i]); //物品详情
            listItems.add(map);
        }
        return listItems;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值