这个效果的完成主要分为两个部分
自定义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列表信息滑动删除功能所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)