Scrollview回彈效果自定義控件


滾動回彈效果分析:
首先,創建一個類,繼承scrollview,重寫ontouch事件,實現伸縮回彈效果。
scroollview節點下只能有一個子節點,這個子節點就是我們要移動的view布局。
 
第一步:獲取要操作的子view布局
第二步:重寫onTouch事件監聽
 
 
分析具體事件:
觀察分析得出結論:
讓布局移動每一次拉動的Y軸一半的距離,然后松手滾動[攜帶動畫]回到原來的位置。
下拉或者上拉的時候,記錄按下時的Y軸位置
action_down
 
移動過程中的處理:
計算上一次與本次的Y軸(拉動距離)[而不是按下時候的Y值,和現在移動到的Y值,是每上一次和本次的Y值比較
判斷是否需要移動布局的情況:Y軸的一個距離偏移
 
//2種情況,隨着布局的拖動, inner.getMeasuredHeight()的值是變化的
//inner.getMeasuredHeight()與getHeight()的區別:
當屏幕可以包裹內容的時候,他們的值相等
當view的高度超出屏幕時,getMeasuredHeight()是實際View的大小,與屏幕無關,getHeight的大小此時則是屏幕的大小。
此時,getMeasuredHeight() = getHeight+超出部分。
 
抬起的處理:布局回滾到正常位置
移動動畫回滾到正常位置(*:動畫執行期間,不允許拖拉操作)   
距離:-的滾動距離
public class MyScrollview extends ScrollView {

    //要操作的布局
    private View innerView;
    private float y;
    private Rect normal = new Rect();
    private boolean animationFinish = true;

    public MyScrollview(Context context) {
        super(context, null);
    }

    public MyScrollview(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyScrollview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        int childCount = getChildCount();
        if (childCount > 0) {
            innerView = getChildAt(0);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (innerView == null) {
            return super.onTouchEvent(ev);
        } else {
            commonTouchEvent(ev);
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 自定義touch事件處理
     *
     * @param ev
     */
    private void commonTouchEvent(MotionEvent ev) {
        if (animationFinish) {
            int action = ev.getAction();
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    y = ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float preY = y == 0 ? ev.getY() : y;
                    float nowY = ev.getY();
                    int detailY = (int) (preY - nowY);
                    y = nowY;
                    //操作view進行拖動detailY的一半
                    if (isNeedMove()) {
                        //布局改變位置之前,記錄一下正常狀態的位置
                        if (normal.isEmpty()) {
                            normal.set(innerView.getLeft(), innerView.getTop(), innerView.getRight(), innerView.getBottom());
                        }
                        innerView.layout(innerView.getLeft(), innerView.getTop() - detailY / 2, innerView.getRight(), innerView.getBottom() - detailY / 2);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    y = 0;
                    //布局回滾到原來的位置
                    if (isNeedAnimation()) {
                        animation();
                    }
                    break;
            }
        }
    }

    private void animation() {
        TranslateAnimation ta = new TranslateAnimation(0, 0, 0, normal.top - innerView.getTop());
        ta.setDuration(200);
        ta.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                animationFinish = false;
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                innerView.clearAnimation();
                innerView.layout(normal.left, normal.top, normal.right, normal.bottom);
                normal.setEmpty();
                animationFinish = true;
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        innerView.startAnimation(ta);
    }

    /**
     * 判斷是否需要回滾
     *
     * @return
     */
    private boolean isNeedAnimation() {
        return !normal.isEmpty();
    }

    /**
     * 判斷是否需要移動
     *
     * @return
     */
    private boolean isNeedMove() {
        int offset = innerView.getMeasuredHeight() - getHeight();
        int scrollY = getScrollY();
        Log.e("zoubo", "getMeasuredHeight:" + innerView.getMeasuredHeight() + "----getHeight:" + getHeight());
        Log.e("zoubo", "offset:" + offset + "----scrollY:" + scrollY);
        if (scrollY == 0 || scrollY == offset) {
            return true;
        }
        return false;
    }
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM