Android开发中模仿qq列表信息滑动删除功能

Android开发中模仿qq列表信息滑动删除功能,第1张

概述这个效果的完成主要分为两个部分自定义view作为listview的列表项一个view里面包括显示头像,名字,消息内容等的contentView和滑动才能显示出来的删除,置顶的右边菜单menuView在手指移动的时候同时改变这两个视图的位

这个效果的完成主要分为两个部分

自定义view作为ListvIEw的列表项 一个vIEw里面包括 显示头像,名字,消息内容等的contentVIEw和滑动才能显示出来的删除,置顶的右边菜单menuVIEw 在手指移动的时候同时改变这两个视图的位置

重写ListvIEw 判断item向左还是向右滑动 正常的滚动还是左右滑动等等 重写ontouchEvent 进行事件分发

大致思路:

ListvIEw进行事件分发,判断需要滑动还是滚动等状态,如果需要滑动将事件传递给item进行滑动处理. 在item中控制contentVIEw和menuVIEw进行位置的变化完成滚动效果

重写ListvIEw代码

public class SlIDeListVIEw extends ListVIEw{  private SlIDeItem mtouchVIEw=null;//记录当前点击的item VIEw  private float mDownX;//x轴坐标  private float mDownY;//y轴坐标  private int mtouchState;//记录点击状态  private int mtouchposition;//记录点击位置  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 static final int MAX_Y=5;  private static final int MAX_X=3;  public SlIDeListVIEw(Context context) {    super(context);  }  public SlIDeListVIEw(Context context,AttributeSet attrs) {    super(context,attrs);  }  public SlIDeListVIEw(Context context,AttributeSet attrs,int defStyleAttr) {    super(context,attrs,defStyleAttr);  }  @OverrIDe  public boolean ontouchEvent(MotionEvent ev) {    if (ev.getAction() != MotionEvent.ACTION_DOWN && mtouchVIEw == null)      return super.ontouchEvent(ev);    switch (ev.getAction()) {      case MotionEvent.ACTION_DOWN:        //按住的item的position        int oldposition = mtouchposition;        //记录位置        mDownX = ev.getX();        mDownY = ev.getY();        mtouchState = touch_STATE_NONE;        //根据当前横纵坐标点获取点击的item的position        mtouchposition = this.pointToposition((int) ev.getX(),(int) ev.getY());        //判断当前点击的是否和上次点击的item是同一个,如果是同一个,并且状态是打开了的就记录状态和坐标        //记录坐标通过Item中的downX属性        if (mtouchposition == oldposition && mtouchVIEw != null && mtouchVIEw.isopen()) {          mtouchState = touch_STATE_X;          mtouchVIEw.onSwipe(ev);          return true;        }        //获取当前的item的VIEw        VIEw currentVIEw = getChildAt(mtouchposition - getFirstVisibleposition());        //如果不是同一个item 那么点击的话就关闭掉之前打开的item        if (mtouchVIEw != null && mtouchVIEw.isopen()) {          mtouchVIEw.smoothCloseMenu();          mtouchVIEw = null;          return super.ontouchEvent(ev);        }        //判断该vIEw的类型        if (currentVIEw instanceof SlIDeItem) {          mtouchVIEw = (SlIDeItem) currentVIEw;        }        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);          }          return true;        } else if (mtouchState == touch_STATE_NONE) {          //判断滑动方向,x方向执行滑动,Y方向执行滚动          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);  }}

重写item项

vIEw的滑动效果都是在里完成的 使用了Scroller类

关于Scroller的使用文章最后已经粘出了大神的帖子 不懂的同学可以先把Scroller的使用理解了在看这个滑动效果就很好懂了 我在这里简单讲讲

这个类的并没有实际的完成滚动效果 它是一个计算控件移动轨迹的辅助类,
比如说:在1秒内从位置0移动到位置100 这个类会计算出移动的数值,它并没有完成滑动的效果,但是告诉了我们这个滑动的过程 实际的上的vIEw移动 *** 作在computeScroll()完成 这个方法是vIEw的自带方法 需要我们重写

computeScroll方法又是怎么情况呢 看源码 本身是个空的 就等着我们实现 我们实际改变vIEw位置的代码就是在此方法内调用的

额。。。英语一般

大致意思 我们要通过Scroller实现一个滚动效果的时候 父布局就会调用此方法来完成子视图的位置更新

官方的描述是:当我们执行ontouch或invalIDate()或postInvalIDate()都会导致这个方法的执行

在此方法中不断的获取到移动的距离 通过vIEw自带的layout()方法更新vIEw所在位置

 /**   * Called by a parent to request that a child update its values for mScrollX   * and mScrollY if necessary. This will typically be done if the child is   * animating a scroll using a {@link androID.Widget.Scroller Scroller}   * object.   */  public voID computeScroll() {  }public class SlIDeItem extends linearLayout {  private VIEw contentVIEw = null; //不滑动显示的vIEw  private VIEw menuVIEw = null; //左滑显示的vIEw  //计算滑动 动画效果  private Scroller mOpenScroller;  private Scroller mCloseScroller;  private int downX; //开始按下的位置  //记录状态  private int state = STATE_CLOSE;  private static final int STATE_CLOSE = 0;  private static final int STATE_OPEN = 1;  private int mBaseX;//在关闭滑动的时候计算与父布局的剩余距离  public SlIDeItem(Context context) {    super(context);  }  public SlIDeItem(Context context,attrs);  }  public SlIDeItem(Context context,defStyleAttr);  }  public voID setContentVIEw(VIEw contentVIEw,VIEw rightVIEw){    this.contentVIEw = contentVIEw;    this.menuVIEw = rightVIEw;    //初始化mColoseScroller和mOpenScroller    mCloseScroller=new Scroller(getContext());    mOpenScroller = new Scroller(getContext());    initVIEw();  }  //child vIEw的布局参数设定好后 添加到parent vIEw里面  private voID initVIEw() {    //这是设置宽和高    LayoutParams contentParams = new LayoutParams        (LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);    LayoutParams rightParams=new LayoutParams        (LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);    contentVIEw.setLayoutParams(contentParams);    contentVIEw.setpadding(10,10,10);    menuVIEw.setLayoutParams(rightParams);    this.addVIEw(contentVIEw);    this.addVIEw(menuVIEw);  }  // 判断是否滑出的状态  public boolean isopen() {    return state == STATE_OPEN;  }  /**   * 供ListVIEw调用 进行视图的移动  ListVIEw判断状态 什么情况下左滑   * @param event   * @return   */  public boolean onSwipe(MotionEvent event) {    switch (event.getAction()) {      case MotionEvent.ACTION_DOWN:        downX = (int) event.getX();        break;      case MotionEvent.ACTION_MOVE:        //按下位置减去移动位置 获取移动的距离        int dis = (int) (downX - event.getX());        if (state == STATE_OPEN) {          dis += menuVIEw.getWIDth();        }        //移动        move(dis);        break;      case MotionEvent.ACTION_UP:        //当滑到右边视图一半的距离 自动滑进滑出        if ((downX - event.getX()) > (menuVIEw.getWIDth() / 2)) {          smoothOpenMenu();        } else {          smoothCloseMenu();          return false;        }        break;    }    //消费掉事件    return true;  }  /**   * 视图重新绘制时调用   */  @OverrIDe  public voID computeScroll() {    if (state == STATE_OPEN) {      //computeScrollOffset滑动是否结束      if (mOpenScroller.computeScrollOffset()) {        move(mOpenScroller.getCurrX());        postInvalIDate();      }    } else {      if (mCloseScroller.computeScrollOffset()) {        move(mBaseX - mCloseScroller.getCurrX());        postInvalIDate();      }    }  }  /**   * 移动视图   * @param dis   */  private voID move(int dis) {    //这两个判断是为了保证 不要把视图移动过多 导致视图偏移    if (dis > menuVIEw.getWIDth()) {      dis = menuVIEw.getWIDth();    }    if (dis < 0) {      dis = 0;    }    //vIEw.layout()控制vIEw相对于其父布局的位置  在触发移动的时候调用不断改变位置 完成实际的滑动效果    contentVIEw.layout(-dis,contentVIEw.gettop(),contentVIEw.getWIDth() - dis,getMeasuredHeight());    menuVIEw.layout(contentVIEw.getWIDth() - dis,menuVIEw.gettop(),contentVIEw.getWIDth() + menuVIEw.getWIDth() - dis,menuVIEw.getBottom());  }  /**   * 滑动关闭   * contentVIEw.getleft() 与其父视图的相对位置   */  public voID smoothCloseMenu() {    state = STATE_CLOSE;    mBaseX = -contentVIEw.getleft();    mCloseScroller.startScroll(0,mBaseX,350);    postInvalIDate();  }  /**   * 滑动打开   */  public voID smoothOpenMenu() {    state = STATE_OPEN;    mOpenScroller.startScroll(-contentVIEw.getleft(),menuVIEw.getWIDth(),350);    postInvalIDate();  }  @OverrIDe  protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) {    super.onMeasure(wIDthMeasureSpec,heightmeasureSpec);    if(menuVIEw != null)      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) {    //确保centerVIEw menuVIEw的显示位置    if(contentVIEw != null)      contentVIEw.layout(0,getMeasureDWIDth(),contentVIEw.getMeasuredHeight());    if(menuVIEw != null)      menuVIEw.layout(getMeasureDWIDth(),getMeasureDWIDth() + menuVIEw.getMeasureDWIDth(),contentVIEw.getMeasuredHeight());  }}

适配器

public class SlIDeAdapter extends BaseAdapter implements VIEw.OnClickListener{  private List<String> dataList;  private Context context;  private LayoutInflater inflater;  public SlIDeAdapter(Context context,List<String> dataList) {    this.context = context;    this.dataList = dataList;    this.inflater=LayoutInflater.from(context);  }  @OverrIDe  public int getCount() {    return 5;  }  @OverrIDe  public Object getItem(int position) {    return null;  }  @OverrIDe  public long getItemID(int position) {    return 0;  }  @OverrIDe  public VIEw getVIEw(int position,VIEw convertVIEw,VIEwGroup parent) {    VIEwHolder holder=null;    if (convertVIEw==null){      VIEw content=inflater.inflate(R.layout.adapter_item_content,null);      VIEw menu=inflater.inflate(R.layout.adapter_item_menu,null);      holder=new VIEwHolder(content,menu);      SlIDeItem slIDeItem=new SlIDeItem(context);      slIDeItem.setContentVIEw(content,menu);      convertVIEw=slIDeItem;      convertVIEw.setTag(holder);    }else {      holder= (VIEwHolder) convertVIEw.getTag();    }    holder.itemTvDelete.setonClickListener(this);    holder.itemTvnoread.setonClickListener(this);    holder.itemTvTotop.setonClickListener(this);    return convertVIEw;  }  class VIEwHolder{    TextVIEw itemTvTotop;    TextVIEw itemTvnoread;    TextVIEw itemTvDelete;    public VIEwHolder(VIEw center,VIEw menu) {      this.itemTvTotop = (TextVIEw) menu.findVIEwByID(R.ID.item_to_top);      this.itemTvnoread = (TextVIEw) menu.findVIEwByID(R.ID.item_no_read);      this.itemTvDelete = (TextVIEw) menu.findVIEwByID(R.ID.item_delete);    }  }  @OverrIDe  public voID onClick(VIEw v) {    switch (v.getID()){      case R.ID.item_no_read:        Toast.makeText(context,"标为未读",Toast.LENGTH_SHORT).show();        break;      case R.ID.item_to_top:        Toast.makeText(context,"置顶了熬",Toast.LENGTH_SHORT).show();        break;      case R.ID.item_delete:        Toast.makeText(context,"删除啦",Toast.LENGTH_SHORT).show();        break;    }  }}

参考文档:

SwipeMenuListView github上的实现此效果的开源项目

以上所述是小编给大家介绍的AndroID开发模仿qq列表信息滑动删除功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!

总结

以上是内存溢出为你收集整理的Android开发中模仿qq列表信息滑动删除功能全部内容,希望文章能够帮你解决Android开发中模仿qq列表信息滑动删除功能所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1147289.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存