您的位置:首页 > 其它

ListView弹性下拉效果

2015-12-20 13:31 337 查看
开源项目地址:https://github.com/chiemy/PullSeparateListView

效果图:



用什么实现的?

通过属性动画和事件分发机制实现的。

只分析实现原理和关键代码:

1.自定义一个View继承ListView

public class PullSeparateListView extends ListView
{

}


2.复写ListView的dispatchTouchEvent方法

// 核心代码
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
float currentY = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
float downX = ev.getX();
float downY = ev.getY();
// 记录按下位置,当isSeparateAll()返回false时,会用到
originDownPosition = pointToPosition((int) downX, (int) downY);
downPosition = originDownPosition - getFirstVisiblePosition();
if (showDownAnim) {
performDownAnim(downPosition);
}
break;
case MotionEvent.ACTION_MOVE:
// 记录到达顶部或底部时手指的位置
if (!separate) {
startY = currentY;
}
deltaY = currentY - startY;

// 到达顶部
if (reachTop) {
if (!separateFromTop(currentY)) {
return super.dispatchTouchEvent(ev);
}
return false;
}
// 到达底部
if (reachBottom) {
if (!separateFromBottom(currentY)) {
return super.dispatchTouchEvent(ev);
}
return false;
}
preY = currentY;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
preY = 0;
recoverDownView();
if (separate) {
separate = false;
recoverSeparate();
// 移动,不响应点击事件
if (move) {
move = false;
return false;
}
}
break;
}
return super.dispatchTouchEvent(ev);
}


3.在dispatchTouchEvent的MotionEvent.ACTION_MOVE事件中检测有没有滑动到最顶部和最底部,如果滑动到最底部则执行上拉的弹性效果。如果滑动到最顶部则实现下拉的弹性效果。

case MotionEvent.ACTION_MOVE:
// 记录到达顶部或底部时手指的位置
if (!separate) {
startY = currentY;
}
deltaY = currentY - startY;

// 到达顶部
if (reachTop) {
if (!separateFromTop(currentY)) {
return super.dispatchTouchEvent(ev);
}
return false;
}
// 到达底部
if (reachBottom) {
if (!separateFromBottom(currentY)) {
return super.dispatchTouchEvent(ev);
}
return false;
}
preY = currentY;
break;


4.弹性效果的实现,for循环遍历每一个Item,根据每个item的索引(position),计算每一个item在Y方向上的偏移量,在每个item的Y方向执行属性动画。

for (int index = 0; index < getChildCount(); index++) {
View child = getChildAt(index);
int multiple = index;
if (!separateAll) {
if (index > downPosition) {
multiple = Math.max(1, downPosition);
}
}
float distance = multiple * deltaY * FACTOR;
child.setTranslationY(distance);
}


5.松开手指,恢复到原来的状态,实现原理:遍历每一个Item实现,将每一个Y方向上的偏移量(offsetY)置为0,通过属性动画将状态复原。

/**
* 恢复
*/
private void recoverSeparate() {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
ViewPropertyAnimator.animate(child).translationY(0)
.setDuration(SEPARATE_RECOVER_DURATION)
.setInterpolator(new AccelerateInterpolator());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: