Android----仿qq顶部底部弹性ScrollView
2018-04-30 本文已影响289人
pgydbh
目录
无标题1.png演示
gif5新文件.gif思路
当接触到底部,顶部,滑动时记录滑动距离,然后设置内部孩子的layout,松开之后还原。
问题&核心代码
问题1:如何记录滑动距离
答案:定义move,表示当前滑动的距离,不用管理页面滑动距离,因为滑动距离与页面距离有函数关系。
private float move;//移动距离
/**
* 计算滑动高度与实际要移动的高度的关系
* @param move 滑动高度
* @return
*/
private float calculateHeight(float move){
return move / 2;
}
问题2:页面是怎么移动的
答案:这个问题有好几种思路,比如强行加头部,加底部,更改头部底部高度,或者给inner(scrollView的唯一孩子)设置padding,但是考虑应用场景,这里应该是示用改变inner的layout位置(相对于父亲scrollView的位置)是最恰当的方法。
//设置scrollView中唯一孩子的位置
private void setLayout(float move){
inner.layout(normal.left, normal.top + (int) calculateHeight(move), normal.right, normal.bottom + (int) calculateHeight(move));
}
问题3:怎么回去
答案:一次滑动开始时记录位置,检测到抬起时,执行回弹动画。
private Rect normal;//用于存储开始滑动时的位置
else{
lastPosition = ev.getY();
normal.set(inner.getLeft(), inner.getTop(), inner.getRight(), inner.getBottom());
animStop = true;
}
case MotionEvent.ACTION_UP:
replyView(move, 0);
animStop = false;
break;
问题4.如何处理双指滑动
答案:双指滑动有两种情况,这里是第一种情况,一指未抬,另一指头已落下,其实在整个过程中只有一次down事件发生,所以较好处理,为了防止第二指落下距离远离第一指最后move位置,设置检测区间
if (lastPosition != 0){
float temp = ev.getY() - lastPosition;
if (temp > -60 && temp < 60) {
move += temp;
}
lastPosition = ev.getY();
if ((move > 0 && isScrolledToTop) || (move < 0 && isScrolledToBottom)) {
setLayout(move);
}else{
setLayout(0);
move = 0;
lastPosition = 0;
}
}
问题5:如何处理动画移动时出现事件
答案:设置bool值控制动画是不是继续有效,(因为没有想到好的取消动画的办法,cancel无效),动画期间发生事件,控制动画效果失效,接着上次move执行普通滑动。
/**
* 回弹
* @param distance 距离
* @param origin 终点
*/
private void replyView(final float distance, final int origin) {
// 设置动画
anim = ObjectAnimator.ofFloat(distance - origin, 0.0F).setDuration(500);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if (!animStop) {
if (distance > 0) {
move = (float) animation.getAnimatedValue();
setLayout(move);
} else {
move = (float) animation.getAnimatedValue();
setLayout(move);
}
}
}
});
anim.start();
}
case MotionEvent.ACTION_MOVE:
if (!animStop){
lastPosition = ev.getY();
animStop = true;
}
问题6:如何处理关于viewpager
答案:简单之处在于viewpager是横向滑动,而scrollView是竖直滑动,所以设置控制事件阻止数值,
//处理Viewpager
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPrevX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
System.out.println(event.getX() - mPrevX);
if (Math.abs(event.getX() - mPrevX) > 60) {
return false;
}
}
return super.onInterceptTouchEvent(event);
}