惯例,先放效果图,DEMO在最后
想当年博主刚接触Android的时候,看到这个效果心中只有膜拜啊,如果慢慢的自己水平也上来了,就把当年的一个想法给圆满了吧。
好了,废话不多说,先总结总结这个效果:
- 首先是需要自定义ListView,这点是必须的,然后在ListView的onTouchEvent方法中对事件进行处理
- 普通的Item的话,是没办法实现这样侧滑的,即使你塞一个HorizontalScrollView进去都不行,所以也必须自定义一个ItemView实现左右侧滑
- 由于ListView的layout_width不一定是MATCH_PARENT,也可能是定值比如300dp,这个时候我们就需要建立一种机制来保证ItemView的宽度和ListView的宽度匹配,毕竟ItemView包含了两个View,一个是正文的ContentView,一个是菜单的MenuView。
首先我从自定义ListView开始讲起,这个ListView需要完成两件事:事件分发和高度匹配。首先来看高度匹配:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
//宽度适配,改变ItemView的宽度
SlideItemView.Width = width;
for(int i = 0; i < getChildCount(); i++){
SlideItemView item = (SlideItemView) getChildAt(i);
item.resetWidth();
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
这个方法并没有什么难度,得到了ListView的宽度,并且将所有在内存中的ItemView的宽度进行重设。这一步是非常必要的,上面也说了,因为你并不知道实际ListView的宽度,那么还谈什么左右滑动。SlideItemView的resetWidth方法我们放在后面讲解。这里就大概了解一下。
然后是ListView的事件分发,这里就比较重要了:
@Override
public boolean onTouchEvent(MotionEvent ev) {
float dx = 0;
float dy = 0;
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
mTouchX = ev.getX();
mTouchY = ev.getY();
mMoveX = ev.getX();
mMoveY = ev.getY();
mTouchPosition = pointToPosition((int)ev.getX(), (int)ev.getY());
break;
case MotionEvent.ACTION_MOVE:
dx = ev.getX() - mMoveX;
dy = ev.getY() - mMoveY;
if(Math.abs(dx) > Math.abs(dy)){
//根据坐标点得到索引值
int position = pointToPosition((int)ev.getX(), (int)ev.getY());
if(mTouchPosition != ListView.INVALID_POSITION && position == mTouchPosition){
//得到内存中真实的Item
SlideItemView itemView = (SlideItemView) getChildAt(position - getFirstVisiblePosition());
itemView.scroll((int) dx);
}
}
mMoveX = ev.getX();
mMoveY = ev.getY();
break;
case MotionEvent.ACTION_UP:
dx = ev.getX() - mTouchX;
dy = ev.getY() - mTouchY;
if(Math.abs(dx) > Math.abs(dy) && Math.abs(dx) >= mTouchSlop){
int position = pointToPosition((int)ev.getX(), (int)ev.getY());
if(mTouchPosition != ListView.INVALID_POSITION && position == mTouchPosition){
//得到真正在内存中的Item
SlideItemView itemView = (SlideItemView) getChildAt(position - getFirstVisiblePosition());
//根据当前scrollX以及dx判断是否显示正文内容
if (itemView.shouldShowContent((int) dx)){
itemView.showContent();
}else{
itemView.showMenu();