Scrollview回彈效果自定義控件

滾動回彈效果分析:
首先,創建一個類,繼承scrollview,重寫ontouch事件,實現伸縮回彈效果。
[scroollview節點下只能有一個子節點,這個子節點就是我們要移動的view佈局]
 
第一步:獲取要操作的子view佈局
第二步:重寫onTouch事件監聽
 
 
分析具體事件:
觀察分析得出結論:
讓佈局移動每一次拉動的Y軸一半的距離,然後鬆手滾動[攜帶動畫]回到原來的位置。
下拉或者上拉的時候,記錄按下時的Y軸位置
action_down:
y
 
移動過程中的處理:
計算上一次與本次的Y軸(拉動距離)[而不是按下時候的Y值,和現在移動到的Y值,是每上一次和本次的Y值比較
判斷是否需要移動佈局的情況:Y軸的一個距離偏移
 
//2種情況,隨着佈局的拖動, inner.getMeasuredHeight()的值是變化的
//inner.getMeasuredHeight()與getHeight()的區別:
當屏幕可以包裹內容的時候,他們的值相等
當view的高度超出屏幕時,getMeasuredHeight()是實際View的大小,與屏幕無關,getHeight的大小此時則是屏幕的大小。
此時,getMeasuredHeight() = getHeight+超出部分。
 
擡起的處理:佈局回滾到正常位置
移動動畫回滾到正常位置(*:動畫執行期間,不允許拖拉操作)   
距離:-的滾動距離
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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;
    }
}
發佈了6 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章