侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 129847 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

android实现QQ微信侧滑删除效果

2023-06-03 星期六 / 0 评论 / 0 点赞 / 33 阅读 / 18266 字

最近由于项目需求,需要做一个listview中的item策划删除的效果,与是查找资料和参考了一些相关的博客,终于完美实现了策划删除的效果。先看一下效果图(研究了半天竟然没研究出来真机上gif图怎么做,大家将就看一下吧)。

最近由于项目需求,需要做一个listview中的item策划删除的效果,与是查找资料和参考了一些相关的博客,终于完美实现了策划删除的效果。

先看一下效果图(研究了半天竟然没研究出来真机上gif图怎么做,大家将就看一下吧)。

     

侧滑效果图


点击删除后的截图


点击删除后,listview中的第一个“微信团队”被删除。

接下来看代码部分,很多注释都在代码中,直接上代码。

首先自定义个SlideView继承LinearLayout。

.
import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.Scroller; import android.widget.TextView;  /**   * SlideView 继承自LinearLayout   */  public class SlideView extends LinearLayout {      private static final String TAG = "SlideView";      private Context mContext;      // 用来放置所有view的容器    private LinearLayout mViewContent;      // 用来放置内置view的容器,比如删除 按钮    private RelativeLayout mHolder;      // 弹性滑动对象,提供弹性滑动效果    private Scroller mScroller;      // 滑动回调接口,用来向上层通知滑动事件    private OnSlideListener mOnSlideListener;      // 内置容器的宽度 单位:dp    private int mHolderWidth = 120;      // 分别记录上次滑动的坐标    private int mLastX = 0;    private int mLastY = 0;      // 用来控制滑动角度,仅当角度a满足如下条件才进行滑动:tan a = deltaX / deltaY > 2    private static final int TAN = 2;      public interface OnSlideListener {      // SlideView的三种状态:开始滑动,打开,关闭      public static final int SLIDE_STATUS_OFF = 0;      public static final int SLIDE_STATUS_START_SCROLL = 1;      public static final int SLIDE_STATUS_ON = 2;        public void onSlide(View view, int status);    }      public SlideView(Context context) {      super(context);      initView();    }      public SlideView(Context context, AttributeSet attrs) {      super(context, attrs);      initView();    }      private void initView() {      mContext = getContext();      // 初始化弹性滑动对象      mScroller = new Scroller(mContext);      // 设置其方向为横向      setOrientation(LinearLayout.HORIZONTAL);      // 将slide_view_merge加载进来      View.inflate(mContext, R.layout.slide_view_merge, this);      mViewContent = (LinearLayout) findViewById(R.id.view_content);      mHolderWidth = Math.round(TypedValue.applyDimension(          TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources()              .getDisplayMetrics()));    }      // 设置按钮的内容,也可以设置图标啥的,我没写    public void setButtonText(CharSequence text) {      ((TextView) findViewById(R.id.delete)).setText(text);    }      // 将view加入到ViewContent中    public void setContentView(View view) {      mViewContent.addView(view);    }      // 设置滑动回调    public void setOnSlideListener(OnSlideListener onSlideListener) {      mOnSlideListener = onSlideListener;    }      // 将当前状态置为关闭    public void shrink() {      if (getScrollX() != 0) {        this.smoothScrollTo(0, 0);      }    }      // 根据MotionEvent来进行滑动,这个方法的作用相当于onTouchEvent    // 如果你不需要处理滑动冲突,可以直接重命名,照样能正常工作    public void onRequireTouchEvent(MotionEvent event) {      int x = (int) event.getX();      int y = (int) event.getY();      int scrollX = getScrollX();      Log.d(TAG, "x=" + x + " y=" + y);        switch (event.getAction()) {      case MotionEvent.ACTION_DOWN: {        if (!mScroller.isFinished()) {          mScroller.abortAnimation();        }        if (mOnSlideListener != null) {          mOnSlideListener.onSlide(this,              OnSlideListener.SLIDE_STATUS_START_SCROLL);        }        break;      }      case MotionEvent.ACTION_MOVE: {        int deltaX = x - mLastX;        int deltaY = y - mLastY;        if (Math.abs(deltaX) < Math.abs(deltaY) * TAN) {          // 滑动不满足条件,不做横向滑动          break;        }          // 计算滑动终点是否合法,防止滑动越界        int newScrollX = scrollX - deltaX;        if (deltaX != 0) {          if (newScrollX < 0) {            newScrollX = 0;          } else if (newScrollX > mHolderWidth) {            newScrollX = mHolderWidth;          }          this.scrollTo(newScrollX, 0);        }        break;      }      case MotionEvent.ACTION_UP: {        int newScrollX = 0;        // 这里做了下判断,当松开手的时候,会自动向两边滑动,具体向哪边滑,要看当前所处的位置        if (scrollX - mHolderWidth * 0.75 > 0) {          newScrollX = mHolderWidth;        }        // 慢慢滑向终点        this.smoothScrollTo(newScrollX, 0);        // 通知上层滑动事件        if (mOnSlideListener != null) {          mOnSlideListener.onSlide(this,              newScrollX == 0 ? OnSlideListener.SLIDE_STATUS_OFF                  : OnSlideListener.SLIDE_STATUS_ON);        }        break;      }      default:        break;      }        mLastX = x;      mLastY = y;    }      private void smoothScrollTo(int destX, int destY) {      // 缓慢滚动到指定位置      int scrollX = getScrollX();      int delta = destX - scrollX;      // 以三倍时长滑向destX,效果就是慢慢滑动      mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3);      invalidate();    }      @Override    public void computeScroll() {      if (mScroller.computeScrollOffset()) {        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());        postInvalidate();      }    }    }
.

自定义SlideView所关联的xml.(主要就是布局侧滑显出来的删除按钮)

.
<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android"   android:layout_width="match_parent"   android:layout_height="match_parent" >    <LinearLayout     android:id="@+id/view_content"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="horizontal" >   </LinearLayout>    <RelativeLayout     android:id="@+id/holder"     android:layout_width="120dp"     android:layout_height="match_parent"     android:clickable="true"     android:background="@drawable/holder_bg">      <TextView       android:id="@+id/delete"       android:layout_width="wrap_content"       android:layout_height="wrap_content"       android:drawableLeft="@drawable/del_icon_normal"       android:layout_centerInParent="true"       android:gravity="center"       android:textColor="@color/floralwhite"       android:text="删除" />   </RelativeLayout>  </merge>
.

自定义ListViewCompat继承Listview。

.
import com.ryg.slideview.MainActivity.MessageItem;  import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ListView;  public class ListViewCompat extends ListView {    private static final String TAG = "ListViewCompat";    private SlideView mFocusedItemView;    public ListViewCompat(Context context) {     super(context);   }    public ListViewCompat(Context context, AttributeSet attrs) {     super(context, attrs);   }    public ListViewCompat(Context context, AttributeSet attrs, int defStyle) {     super(context, attrs, defStyle);   }    public void shrinkListItem(int position) {     View item = getChildAt(position);      if (item != null) {       try {         ((SlideView) item).shrink();       } catch (ClassCastException e) {         e.printStackTrace();       }     }   }    @Override    public boolean onTouchEvent(MotionEvent event) {      switch (event.getAction()) {      case MotionEvent.ACTION_DOWN: {        int x = (int) event.getX();        int y = (int) event.getY();        //根据坐标获取item所在的行        int position = pointToPosition(x, y);        Log.e(TAG, "postion=" + position);        if (position != INVALID_POSITION) {          //得到当前点击行的数据从而取出当前行的item。          //可能有人怀疑,为什么要这么干?为什么不用getChildAt(position)?          //因为ListView会进行缓存,如果你不这么干,有些行的view你是得不到的。          MessageItem data = (MessageItem) getItemAtPosition(position);          mFocusedItemView = data.slideView;          Log.e(TAG, "FocusedItemView=" + mFocusedItemView);        }      }      default:        break;      }          //向当前点击的view发送滑动事件请求,其实就是向SlideView发请求      if (mFocusedItemView != null) {        mFocusedItemView.onRequireTouchEvent(event);      }          return super.onTouchEvent(event);    }   } 
.

接下来就是主界面的activity了

.
import java.util.ArrayList; import java.util.List;  import com.ryg.slideview.SlideView.OnSlideListener;  import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView;  public class MainActivity extends Activity implements OnItemClickListener,  OnClickListener, OnSlideListener {   private static final String TAG = "MainActivity";   private ListViewCompat mListView;   private List<MessageItem> mMessageItems = new ArrayList<MainActivity.MessageItem>();   private SlideAdapter mSlideAdapter;   // 上次处于打开状态的SlideView  private SlideView mLastSlideViewWithStatusOn;   @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  initView();  }   private void initView() {  mListView = (ListViewCompat) findViewById(R.id.list);   for (int i = 0; i < 20; i++) {    MessageItem item = new MessageItem();    if (i % 2 == 0) {      item.iconRes = R.drawable.default_qq_avatar;      item.title = "腾讯新闻";      item.msg = "天津大爆炸:河北大爆炸";      item.time = "晚上18:00";    } else {      item.iconRes = R.drawable.wechat_icon;      item.title = "微信团队";      item.msg = "欢迎你使用微信";      item.time = "10月01日";    }    mMessageItems.add(item);  }  mSlideAdapter = new SlideAdapter();  mListView.setAdapter(mSlideAdapter);  mListView.setOnItemClickListener(this);  }   //listview 的适配器 private class SlideAdapter extends BaseAdapter {   private LayoutInflater mInflater;   SlideAdapter() {    super();    mInflater = getLayoutInflater();  }   @Override  public int getCount() {    return mMessageItems.size();  }   @Override  public Object getItem(int position) {    return mMessageItems.get(position);  }   @Override  public long getItemId(int position) {    return position;  }   @Override  public View getView(int position, View convertView, ViewGroup parent) {    ViewHolder holder;    SlideView slideView = (SlideView) convertView;    if (slideView == null) {      // 这里是我们的item      View itemView = mInflater.inflate(R.layout.list_item, null);       slideView = new SlideView(MainActivity.this);      // 这里把item加入到slideView      slideView.setContentView(itemView);      // 下面是做一些数据缓存      holder = new ViewHolder(slideView);      slideView.setOnSlideListener(MainActivity.this);      slideView.setTag(holder);    } else {      holder = (ViewHolder) slideView.getTag();    }    MessageItem item = mMessageItems.get(position);    item.slideView = slideView;    item.slideView.shrink();     holder.icon.setImageResource(item.iconRes);    holder.title.setText(item.title);    holder.msg.setText(item.msg);    holder.time.setText(item.time);    holder.deleteHolder.setOnClickListener(MainActivity.this);     return slideView;  }   }   public class MessageItem {  public int iconRes;  public String title;  public String msg;  public String time;  public SlideView slideView;  }   private static class ViewHolder {  public ImageView icon;  public TextView title;  public TextView msg;  public TextView time;  public ViewGroup deleteHolder;   ViewHolder(View view) {    icon = (ImageView) view.findViewById(R.id.icon);    title = (TextView) view.findViewById(R.id.title);    msg = (TextView) view.findViewById(R.id.msg);    time = (TextView) view.findViewById(R.id.time);    deleteHolder = (ViewGroup) view.findViewById(R.id.holder);  }  }   @Override  public void onItemClick(AdapterView<?> parent, View view, int position,    long id) {  // 这里处理ListItem的点击事件  Log.e(TAG, "onItemClick position=" + position);  }   @Override  public void onSlide(View view, int status) {  // 如果当前存在已经打开的SlideView,那么将其关闭  if (mLastSlideViewWithStatusOn != null      && mLastSlideViewWithStatusOn != view) {    mLastSlideViewWithStatusOn.shrink();  }  // 记录本次处于打开状态的view  if (status == SLIDE_STATUS_ON) {    mLastSlideViewWithStatusOn = (SlideView) view;  }  }   @Override  public void onClick(View v) {  // 这里处理删除按钮的点击事件,可以删除对话  if (v.getId() == R.id.holder) {    int position = mListView.getPositionForView(v);    if (position != ListView.INVALID_POSITION) {      mMessageItems.remove(position);      mSlideAdapter.notifyDataSetChanged();    }    Log.e(TAG, "onClick v=" + v);  }  } 
.

主界面中activity用到的xml

.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   xmlns:tools="http://schemas.android.com/tools"   android:layout_width="match_parent"   android:layout_height="match_parent" >    <com.ryg.slideview.ListViewCompat     android:id="@+id/list"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:background="#fff4f7f9"     android:cacheColorHint="#00000000"     android:divider="#dddbdb"     android:dividerHeight="1.0px"     android:drawSelectorOnTop="false"     android:listSelector="@android:color/transparent"     android:scrollbars="none" />  </LinearLayout>
.

listview适配器的布局。

.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"   xmlns:tools="http://schemas.android.com/tools"   android:layout_width="match_parent"   android:layout_height="58dp"   android:background="@drawable/list_item_bg"   android:descendantFocusability="blocksDescendants"   android:gravity="center_vertical"   android:paddingBottom="5dp"   android:paddingLeft="10dp"   android:paddingRight="10dp"   android:paddingTop="5dp" >    <ImageView     android:id="@+id/icon"     android:layout_width="50dp"     android:layout_height="50dp"     android:layout_marginRight="5dp"     android:src="@drawable/wechat_icon" />    <TextView     android:id="@+id/title"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_toRightOf="@id/icon"     android:textColor="@color/black"     android:textSize="15sp" />    <TextView     android:id="@+id/msg"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignBottom="@id/icon"     android:layout_alignLeft="@id/title"     android:textColor="@color/grey" />    <TextView     android:id="@+id/time"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignParentRight="true"     android:layout_alignTop="@id/title"     android:textColor="@color/grey" />  </RelativeLayout>
.

附drawable目录下的xml文件
holder_bg.xml

.
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:drawable="@color/dimgrey" android:state_pressed="true"></item>   <item android:drawable="@color/dimgrey" android:state_focused="true"></item>   <item android:drawable="@color/dimgrey" android:state_selected="true"></item>   <item android:drawable="@color/gray" android:state_enabled="true"></item>   <item android:drawable="@color/gray" android:state_enabled="false"></item>  </selector> 
.

list_item_bg.xml.

.
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:drawable="@drawable/item_point_bg" android:state_pressed="true"></item>   <item android:drawable="@drawable/item_point_bg" android:state_focused="true"></item>   <item android:drawable="@drawable/item_point_bg" android:state_selected="true"></item>   <item android:drawable="@android:color/transparent" android:state_enabled="true"></item>   <item android:drawable="@android:color/transparent" android:state_enabled="false"></item>  </selector>
.

还有一些对color颜色的定义,这里就不贴了,大家可以直接换成颜色的代码就可以。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持..。

广告 广告

评论区