说明:
说明:可横向滑动的ListView(包含固定列和滚动列),本示例重点在列表可横向滚动时涉及的手势以及滚动距离计算,不过只是Demo给出思路,细节没有处理,也没有进行完善。
动画效果:
布局说明:
对应代码目录结构:
主要类以及方法说明:
1、DragableListViewItem.java类中动态创建每行Item的布局方法
/**
* 动态创建每行Item的布局
* @param viewGroup :每行item的父容器(有固定列和非固定列2种父容器)
* @param index:列数索引
* @param value :文本值
*/
public void setValue(ViewGroup viewGroup, int index, String value) {
TextView t;
LayoutParams l;
if (viewGroup.getChildCount() > index) {
t = (TextView) viewGroup.getChildAt(index);
} else {
t = (TextView) inflater.inflate(R.layout.column_dragable_list_item_cell, null);
if (viewGroup == contentColumn) {
t.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
l = new LayoutParams(columnWidth, height);
} else {
t.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
l = new LayoutParams(columnWidth, height);
}
viewGroup.addView(t, l);
}
t.setText(value);
}
2、listView的onTouch事件 处理横向滑动。关键点已经注释,该onTouchEvent方法中涉及到的其他一些方法,比如getMoveItemScrollX等也已在相应方法中做了注释。
/*
* 横向滑动的核心方法
* */
public boolean onTouchEvent(MotionEvent ev) {
if (mVelocityTracker == null)
mVelocityTracker = VelocityTracker.obtain();//手势滑动事件跟踪器
mVelocityTracker.addMovement(ev);
int action = ev.getAction();
float x = ev.getX();
float y = ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mIsDragging = false;//是否处于滑动状态,置为false
mLastMotionX = x;
mLastMotionDownX = x;
mLastMotionDownY = y;
break;
case MotionEvent.ACTION_MOVE:
int xDiff = (int) Math.abs(x - this.mLastMotionDownX);//
int yDiff = (int) Math.abs(y - this.mLastMotionDownY);
//滑动距离大于mTouchSlop时才认为是滑动事件
if ((xDiff > mTouchSlop) && (xDiff > yDiff * 2))
this.mIsDragging = true;
if (mIsDragging) {
if (x > mLastMotionX) { //向右滑动
mDirection = DIRECTION_RIGHT;
} else {
mDirection = DIRECTION_LEFT;
}
int deltaX = (int) (mLastMotionX - x);//滑动的距离
mLastMotionX = x;//别忘记赋值
if (isCanScrollAble()) {
if (deltaX < 0) {//向右滑动
if (getMoveItemScrollX() > 0) {
//Math.max(-getMoveItemScrollX(), deltaX)
//向右滑动时,手指滑动过的距离大于已经左滑的部分时,以左滑宽度为准,
//否则,以手势滑动距离为的实际的偏移值。
itemScrollBy(Math.max(-getMoveItemScrollX(), deltaX), 0);
}
} else if (deltaX > 0) { //向左滑动
int availableToScroll = getAvailableToScroll();
if (availableToScroll > 0) {
//Math.min(availableToScroll, deltaX)
//本次滑动实际的偏移距离:
//手势滑动距离> 可向左滑动的距离时,以可向左滑动的距离为准
//手势滑动距离< 可向左滑动的距离,以手势滑动距离为准
itemScrollBy(Math.min(availableToScroll, deltaX), 0);
}
}
}
}
break;
case MotionEvent.ACTION_UP:
if (mIsDragging) {
VelocityTracker velocity = mVelocityTracker;
velocity.computeCurrentVelocity(1000);//1000毫秒移动了多少距离(速率的单位)
int velocityX = (int) velocity.getXVelocity();//当前的速度
//手指松开后定位到哪一列
if (isCanScrollAble()) {
if (Math.abs(velocityX) < SNAP_VELOCITY) {//当前速度小于500px/s时,就定位到具体列
snapToColumnDestination();
} else {
fling(-velocityX);
}
}
if (velocity != null) {
velocity.recycle();
velocity = null;
}
mIsDragging = false;
ev.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(ev);
}
break;
case MotionEvent.ACTION_CANCEL:
mIsDragging = false;
break;
}
if (!mIsDragging) {
super.onTouchEvent(ev);
}
//必须返回true,因为onTouchEvent中action_down事件返回true,其他后续的move up等事件才能由该listview处理
return true;
}