SoFunction
Updated on 2025-04-05

Android imitation QQ side-sliding delete ListView function example

need:

1. ListView can slide the item sideways, display the delete button, click the delete button, and delete the current item

2. When the delete button is displayed, click the hidden delete button and does not respond to the item click event.

3. When the delete button is hidden, click item to respond to the click event

According to the above requirements, there are also imitation QQ side-sliding codes, but they cannot meet the requirements of 2 and 3. Therefore, I modified it and the code is as follows. Let's take a look at it.

Step 1: Rewrite ListView

public class SwipeListView extends ListView {
  private final static String TAG = "SwipeListView";
  private int mScreenWidth;  // Screen width  private int mDownX;      // Press the x value of the point  private int mDownY;      // Press the y value of the point  private int mDeleteBtnWidth;// Delete the width of the button  private boolean isDeleteShown = false;  // Is the delete button displayed?  private boolean isOnClick = false;
  private ViewGroup mPointChild;  // The item currently processed  private  mLayoutParams;  // LayoutParams of the currently processed item  public SwipeListView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }
  public SwipeListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    // Get screen width    WindowManager wm = (WindowManager) (Context.WINDOW_SERVICE);
    DisplayMetrics dm = new DisplayMetrics();
    ().getMetrics(dm);
    mScreenWidth = ;
  }
  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    switch (()) {
      case MotionEvent.ACTION_DOWN:
        performActionDown(ev);
        break;
      case MotionEvent.ACTION_MOVE:
        return performActionMove(ev);
      case MotionEvent.ACTION_UP:
        return performActionUp(ev);
//        break;
    }
    return (ev);
  }
  // Handle action_down events  private void performActionDown(MotionEvent ev) {
//    (TAG,"performActionDown===="+isDeleteShown);
    if (isDeleteShown) {
      turnToNormal();
    }
    isOnClick = true;
    mDownX = (int) ();
    mDownY = (int) ();
    // Get the item of the current point    int downPosition = pointToPosition(mDownX, mDownY);
    int firstPosition= getFirstVisiblePosition();
    (TAG,"performActionDown====downPosition:"+downPosition+"==firstPosition"+firstPosition);
    if(downPosition < 0) return;
    mPointChild = (ViewGroup) getChildAt(downPosition-firstPosition);
    // Get the width of the delete button    mDeleteBtnWidth = (1).getLayoutParams().width;
    mLayoutParams = () (0)
        .getLayoutParams();
    // Why do you need to reset layout_width equals screen width    // Because when match_parent, no matter how you slide, the delete button will not be displayed.    // why?  Because when match_parent, ViewGroup does not layout the remaining view     = mScreenWidth;
    (0).setLayoutParams(mLayoutParams);
  }
  // Handle action_move event  private boolean performActionMove(MotionEvent ev) {
//    (TAG, "performActionMove====" + isDeleteShown);
    int nowX = (int) ();
    int nowY = (int) ();
    isOnClick = false;
    if ((nowX - mDownX) > (nowY - mDownY)) {
      // If swipe to the left      if (nowX < mDownX) {
        // Calculate the distance to be offset        int scroll = (nowX - mDownX) / 2;
        // If the width of the delete button is greater than the width of the delete button, the maximum width of the delete button is        if (-scroll >= mDeleteBtnWidth) {
          scroll = -mDeleteBtnWidth;
        }
        // Reset leftMargin         = scroll;
        (0).setLayoutParams(mLayoutParams);
      }
      return true;
    }
    return (ev);
  }
  // Handle action_up event  private boolean performActionUp(MotionEvent ev) {
    boolean falg = false;
    if(isOnClick && !isDeleteShown)
    {
      falg = true;
    }
    // If the offset is greater than half of the button, the button will be displayed    // Otherwise, restore the default    if (- >= mDeleteBtnWidth / 2) {
       = -mDeleteBtnWidth;
      isDeleteShown = true;
    } else {
      turnToNormal();
      isDeleteShown = false;
    }
    (0).setLayoutParams(mLayoutParams);
//    (TAG, "performActionUp====" + isDeleteShown);
    if(falg)
    {
      return (ev);
    }
    return true;
  }
  /**
    * Change to normal state
    */
  public void turnToNormal() {
     = 0;
    (0).setLayoutParams(mLayoutParams);
  }
  /**
    * Is it currently available to click
    *
    * @return Is it clickable
    */
  public boolean canClick() {
    return !isDeleteShown;
  }
}

Step 2: Adapter

class SwipeListAdapter extends BaseAdapter {
  @Override
  public int getCount() {
    return ();
  }
  @Override
  public Object getItem(int position) {
    return (position);
  }
  @Override
  public long getItemId(int position) {
    return position;
  }
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    if (null == convertView) {
      holder = new ViewHolder();
      convertView = (, .item_swipe_list, null);
       = (LinearLayout) ();
       = (TextView) (.tv_name);
       = (TextView) ();
      (holder);
    }
    else {
      holder = (ViewHolder) ();
    }
    ((position));
    final int pos = position;
    (new () {
      @Override
      public void onClick(View v) {
        (pos);
        notifyDataSetChanged();
        ();
      }
    });
    return convertView;
  }
}
static class ViewHolder {
  LinearLayout tv;
  TextView tvName;
  TextView delete;
}

Step 3: Write a TestListViewActivity

private SwipeListView mListView;
  private ArrayList<String> mData = new ArrayList<String>() {
    {
      for (int i = 0; i < 20; i++) {
        add("hello world, hello android " + i);
      }
    }
  };
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    (savedInstanceState);
    setContentView(.activity_test_list_view);
    Toolbar toolbar = (Toolbar) findViewById();
    setSupportActionBar(toolbar);
    FloatingActionButton fab = (FloatingActionButton) findViewById();
    (new () {
      @Override
      public void onClick(View view) {
        (view, "Replace with your own action", Snackbar.LENGTH_LONG)
            .setAction("Action", null).show();
      }
    });
    mListView = (SwipeListView) findViewById();
    (new SwipeListAdapter());
//    (new () {
//      @Override
//      public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
// (, (position) + "Clicked",//            Toast.LENGTH_SHORT).show();
//        return false;
//      }
//    });
    (new () {
      @Override
      public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        ("SwipeListView", "setOnItemClickListener====" + ());
// (, (position) + "Clicked",//            Toast.LENGTH_SHORT).show();
      }
    });
  }

Step 4: Layout the file

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:andro
  xmlns:tools="/tools"
  xmlns:app="/apk/res-auto" android:layout_width="match_parent"
  android:layout_height="match_parent" 
  app:layout_behavior="@string/appbar_scrolling_view_behavior"
  tools:showIn="@layout/activity_test_list_view"
  tools:context=".">
  <.
    android:
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:cacheColorHint="@android:color/transparent"
    android:listSelector="@android:color/transparent"
    android:divider="@android:color/darker_gray"
    android:dividerHeight="2dp">
  </.>
</RelativeLayout>

Step 5: The layout file of the item

&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout xmlns:andro
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal"&gt;
  &lt;LinearLayout
    android:
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/white"
    android:paddingBottom="20dp"
    android:paddingLeft="10dp"
    android:paddingTop="20dp"&gt;
    &lt;ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:background="@drawable/group_name_rgb"
      android: /&gt;
    &lt;TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textAppearance="?android:attr/textAppearanceLarge"
      android:text="Large Text"
      android:layout_gravity="center_vertical"
      android: /&gt;
  &lt;/LinearLayout&gt;
  &lt;TextView
    android:
    android:layout_width="80dp"
    android:layout_height="match_parent"
    android:background="#FFFF0000"
    android:gravity="center"
    android:paddingLeft="20dp"
    android:paddingRight="20dp"
    android:text="delete"
    android:textColor="@android:color/white" /&gt;
&lt;/LinearLayout&gt;

Key points:

int downPosition = pointToPosition(mDownX, mDownY);

The downPosition gets -1 during use, resulting in an exception in the subsequent method call!

The above is an example of the Android imitation QQ side-sliding delete ListView function introduced by the editor. I hope it will be helpful to everyone. If you have any questions, please leave me a message and the editor will reply to everyone in time. Thank you very much for your support for my website!