目錄

無標題1.png
演示

gif5新文件.gif
思路
當接觸到底部,頂部,滑動時記錄滑動距離,然后設(shè)置內(nèi)部孩子的layout,松開之后還原。
問題&核心代碼
問題1:如何記錄滑動距離
答案:定義move,表示當前滑動的距離,不用管理頁面滑動距離,因為滑動距離與頁面距離有函數(shù)關(guān)系。
private float move;//移動距離
/**
* 計算滑動高度與實際要移動的高度的關(guān)系
* @param move 滑動高度
* @return
*/
private float calculateHeight(float move){
return move / 2;
}
問題2:頁面是怎么移動的
答案:這個問題有好幾種思路,比如強行加頭部,加底部,更改頭部底部高度,或者給inner(scrollView的唯一孩子)設(shè)置padding,但是考慮應(yīng)用場景,這里應(yīng)該是示用改變inner的layout位置(相對于父親scrollView的位置)是最恰當?shù)姆椒ā?/h6>
//設(shè)置scrollView中唯一孩子的位置
private void setLayout(float move){
inner.layout(normal.left, normal.top + (int) calculateHeight(move), normal.right, normal.bottom + (int) calculateHeight(move));
}
問題3:怎么回去
答案:一次滑動開始時記錄位置,檢測到抬起時,執(zhí)行回彈動畫。
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事件發(fā)生,所以較好處理,為了防止第二指落下距離遠離第一指最后move位置,設(shè)置檢測區(qū)間
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:如何處理動畫移動時出現(xiàn)事件
答案:設(shè)置bool值控制動畫是不是繼續(xù)有效,(因為沒有想到好的取消動畫的辦法,cancel無效),動畫期間發(fā)生事件,控制動畫效果失效,接著上次move執(zhí)行普通滑動。
/**
* 回彈
* @param distance 距離
* @param origin 終點
*/
private void replyView(final float distance, final int origin) {
// 設(shè)置動畫
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:如何處理關(guān)于viewpager
//設(shè)置scrollView中唯一孩子的位置
private void setLayout(float move){
inner.layout(normal.left, normal.top + (int) calculateHeight(move), normal.right, normal.bottom + (int) calculateHeight(move));
}
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;
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;
}
}
/**
* 回彈
* @param distance 距離
* @param origin 終點
*/
private void replyView(final float distance, final int origin) {
// 設(shè)置動畫
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;
}
答案:簡單之處在于viewpager是橫向滑動,而scrollView是豎直滑動,所以設(shè)置控制事件阻止數(shù)值,
//處理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);
}