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 ; } } |
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+超出部分。
擡起的處理:佈局回滾到正常位置
移動動畫回滾到正常位置(*:動畫執行期間,不允許拖拉操作)
距離:-的滾動距離
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.