Android----仿qq頂部底部彈性ScrollView

目錄

無標題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

答案:簡單之處在于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);
    }

查看demo

https://github.com/pgyCode/PullUpAndPullDown

總結(jié)

Android事件分發(fā)機制到現(xiàn)在還是很模糊,沒有一個清晰的認識,但是有一種模糊的認識,接下拉如果有時間一定認真研究,總結(jié)其中最核心的東西出來。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容