最近项目需求做一个仿微博的弹性listview,找了很多大家的分享,并没有找到完全符合自己需求的代码,自己在某位热于分享的前辈(看了太多例子,忘记是谁了,请见谅)的代码基础上做了改善,现在记录一下。
public class PullListView extends ListView implements AbsListView.OnScrollListener {
private static final String TAG = "PullListView";
//下拉因子,实现下拉时的延迟效果
private static final float PULL_FACTOR = 0.5f;
//记录刚开始下拉时的触摸位置的Y坐标
private int startY;
private int mlastY;
private int y;
//第一个可见条目的索引
private int firstItemIndex;
//用于实现下拉弹性效果的headView
private View headView2;
private View headView;
private int currentScrollState;
public PullListView(Context context) {
super(context);
init(context);
}
public PullListView(Context context, AttributeSet attr) {
super(context, attr);
init(context);
}
/**
* 初始化
*
* @param context
*/
private void init(Context context) {
//创建PullListView的headview
headView2 = new View(this.getContext());
//默认白色背景,可以改变颜色, 也可以设置背景图片
headView2.setBackgroundColor(Color.WHITE);
//默认高度为0
headView2.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.FILL_PARENT, 0));
this.addHeaderView(headView2);
headView = View.inflate(context, R.layout.activity_main, null);
headView.setPadding(0, dp2px(this.getContext(), -50), 0, dp2px(this.getContext(), -50));
int mScaledTouchSlop = ViewConfiguration.get(getContext())
.getScaledTouchSlop();
this.addHeaderView(headView);
this.setOnScrollListener(this);
}
/**
* 覆盖onTouchEvent方法,实现下拉回弹效果
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (firstItemIndex == 0) {
y = (int) event.getRawY();
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//记录下拉起点状态
startY = y;
break;
case MotionEvent.ACTION_MOVE:
int moveY = y - mlastY; //位移
if (moveY > 0) {
int offset = (int) ((y - startY) * PULL_FACTOR);
Log.i(TAG, "headView.getLayoutParams().height" + headView.getMeasuredHeight());
Log.i(TAG, "headView" + headView.getTop());
if (headView.getPaddingTop() >= 0 && headView.getPaddingBottom() >= 0) {
int top = offset - (dp2px(this.getContext(), 300) - dp2px(this.getContext(), 200));
headView.setPadding(0, 0, 0, 0);
headView2.setLayoutParams(new AbsListView.LayoutParams(MATCH_PARENT, top));
} else {
headView.setPadding(0, offset + dp2px(this.getContext(), -50), 0, offset + dp2px(this.getContext(), -50));
}
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
resetPosition();
break;
}
mlastY = y;
return super.onTouchEvent(event);
}
private void resetPosition() {
headView2.setLayoutParams(new AbsListView.LayoutParams(MATCH_PARENT, 0));
ValueAnimator anim = ValueAnimator.ofInt(headView.getPaddingTop(), dp2px(this.getContext(), -50));
anim.setDuration(200);
anim.start();
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
headView.setPadding(0, (Integer) animation.getAnimatedValue(), 0, (Integer) animation.getAnimatedValue());
}
});
}
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
public int dp2px(Context ctx, float dp) {
float density = ctx.getResources().getDisplayMetrics().density;
int px = (int) (dp * density + 0.5f);// 4.9->5 4.4->4
return px;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
currentScrollState = scrollState;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
firstItemIndex = firstVisibleItem;
}
}