仿知乎详情页
项目需求要求详情页仿照知乎来,从网上扒拉了很长时间,没找到十分合适的,就找了个有相似功能的改了改,感觉还可以,分享下给大家。
主要功能就是当前页的最后展示下一页的一半内容,上拉可以看到部分内容,最后上拉有个viewpager的切换效果,不过改成了上下切换。下拉就是上一页。最难的部分还是在自定义的scrollview上,需要处理里面的各种onTouch事件,费时费力,真是不好做,不过思路基本就是这样吧,不知道知乎原开发者咋写的。
BounceScrollView
重写scrollview来实现。onTouchEvent方法
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mChildView == null || mDisableBounce)
return super.onTouchEvent(ev);
// 默认active的Index
int actionIndex = ev.getActionIndex();
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mScrollPointerId = ev.getPointerId(0);
// Log.e("tenda", "ACTION_DOWN firstPointId:" + firstPointId);
mStart = isHorizontal ? ev.getX() : ev.getY();
onePointerTouch = true;
towPointerTouch = false;
break;
case MotionEvent.ACTION_POINTER_DOWN:
//第二个手指按下
// Log.e("tenda", "ACTION_POINTER_DOWN getPointerCount:" + ev.getPointerCount());
if (ev.getPointerCount() <= 2) {
mScrollPointerId = ev.getPointerId(actionIndex);
mStart = isHorizontal ? ev.getX(mScrollPointerId) : ev.getY(mScrollPointerId);
// Log.e("tenda", "ACTION_POINTER_DOWN secondPointId:" + secondPointId + " firstPointId:" + firstPointId);
onePointerTouch = false;
towPointerTouch = true;
} else {
cancelTouch();
}
break;
case MotionEvent.ACTION_MOVE:
float now, delta;
float dampingDelta;
// 通过pointerID拿到需要处理的Index。
final int index = ev.findPointerIndex(mScrollPointerId);
if (index < 0) {
Log.e("BounceScrollView", "Error processing scroll; pointer index for id "
+ mScrollPointerId + " not found. Did any MotionEvents get skipped?");
return false;
}
now = isHorizontal ? ev.getX(index) : ev.getY(index);
delta = mStart - now;
dampingDelta = (delta / calculateDamping());
mStart = now;
if (mPreDelta <= 0 && dampingDelta > 0) {
onePointerTouch = false;
} else if (mPreDelta >= 0 && dampingDelta < 0) {
onePointerTouch = false;
} else {
onePointerTouch = true;
}
mPreDelta = dampingDelta;
// Log.e("tenda", "delta:" + delta + "dampingDelta:" + dampingDelta);
if (onePointerTouch && canMove(dampingDelta)) {
mOverScrolledDistance += dampingDelta;
// Log.e("tenda", "canMove true mOverScrolledDistance:" + mOverScrolledDistance);
if (isLoad) {
if (mOverScrolledDistance >= 500) {
mOverScrolledDistance = 500;
}
if (getScrollY() == 0) {
//已经到最顶部
break;
}
}
if (isPull) {
if (mOverScrolledDistance <= -200) {
mOverScrolledDistance = -200;
}
if (getScrollY() > 0) {
//已经到最底部
break;
}
}
if (isHorizontal) {
mChildView.setTranslationX(-mOverScrolledDistance);
} else {
mChildView.setTranslationY(-mOverScrolledDistance);
}
if (mOverScrollListener != null) {
// mOverScrollListener.onOverScrolling(mOverScrolledDistance <= 0, Math.abs(mOverScrolledDistance));
if (canMoveFromStart()) {
//下拉
isPull = true;
mOverScrollListener.onPulling(mOverScrolledDistance);
} else {
//上拉
isLoad = true;
mOverScrollListener.onOverScrolling(mOverScrolledDistance <= 0, mOverScrolledDistance);
}
}
} else {
if (isLoad) {
// Log.e("tenda", "mPreDelta:" + mPreDelta + " dampingDelta:" + dampingDelta);
// Log.e("tenda", " isLoad * calculateDamping:" + calculateDamping());
dampingDelta = delta;
mOverScrolledDistance += dampingDelta;
// Log.e("tenda", "canMove false isLoad mOverScrolledDistance:" + mOverScrolledDistance);
mOverScrollListener.onOverScrolling(mOverScrolledDistance <= 0, mOverScrolledDistance);
} else if (isPull) {
// Log.e("tenda", "isPull * calculateDamping:" + calculateDamping());
dampingDelta = delta;
mOverScrolledDistance += dampingDelta;
// Log.e("tenda", "canMove false isPull mOverScrolledDistance:" + mOverScrolledDistance);
mOverScrollListener.onPulling(mOverScrolledDistance);
}
}
break;
case MotionEvent.ACTION_UP:
//最后一个手指松开
// Log.e("tenda", "ACTION_UP");
towPointerTouch = false;
onePointerTouch = false;
cancelTouch();
break;
case MotionEvent.ACTION_POINTER_UP:
//第二个手指松开
onPointerUp(ev);
towPointerTouch = false;
onePointerTouch = true;
break;
case MotionEvent.ACTION_CANCEL:
onePointerTouch = true;
towPointerTouch = false;
cancelTouch();
break;
}
return super.onTouchEvent(ev);
}