仿qq写一个可以来回弹的ScrollView.
只需要重写ScrollView:
public class MyScrollView extends ScrollView {
// y方向上当前触摸点的前一次记录位置
private int previousY = 0;
// y方向上的触摸点的起始记录位置
private int startY = 0;
// y方向上的触摸点当前记录位置
private int currentY = 0;
// y方向上两次移动间移动的相对距离
private int deltaY = 0;
// 第一个子视图
private View childView;
// 用于记录childView的初始位置
private Rect topRect = new Rect();
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@SuppressLint("MissingSuperCall")
@Override
protected void onFinishInflate() {
if (getChildCount() > 0) {
childView = getChildAt(0);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (null == childView) {
return super.dispatchTouchEvent(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startY = (int) event.getY();
previousY = startY;
break;
case MotionEvent.ACTION_MOVE:
currentY = (int) event.getY();
deltaY = previousY - currentY;
previousY = currentY;
if (0 == getScrollY()
|| childView.getMeasuredHeight() - getHeight() <= getScrollY()) {
// 记录childView的初始位置
if (topRect.isEmpty()) {
topRect.set(childView.getLeft(), childView.getTop(),
childView.getRight(), childView.getBottom());
}
// 更新childView的位置
childView.layout(childView.getLeft(), childView.getTop()
- deltaY / 3, childView.getRight(),
childView.getBottom() - deltaY / 3);
}
break;
case MotionEvent.ACTION_UP:
if (!topRect.isEmpty()) {
upDownMoveAnimation();
// 子控件回到初始位置
childView.layout(topRect.left, topRect.top, topRect.right,
topRect.bottom);
}
startY = 0;
currentY = 0;
topRect.setEmpty();
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
// 初始化上下回弹的动画效果
private void upDownMoveAnimation() {
TranslateAnimation animation = new TranslateAnimation(0.0f, 0.0f,
childView.getTop(), topRect.top);
animation.setDuration(100);
animation.setInterpolator(new AccelerateInterpolator());
childView.setAnimation(animation);
}
}
然后想在哪用直接布局就行了。这种重写方法是不会和子控件的点击事件起冲突的。