• 當前位置:首頁 > IT技術 > 移動平臺 > 正文

    Android 自定義ScrollView 支持慣性滑動,慣性回彈效果。支持上拉加載更多
    2021-08-10 19:06:30

    先講下原理:

    ScrollView的子View 主要分為3部分:head頭部,滾動內容,fooder底部

    我們實現慣性滑動,以及回彈,都是靠超過head或者fooder 就重新滾動到? ,內容的頂部或者底部。

    之前看了Pulltorefresh 他是通過不斷改變 head或者 fooder的 pading 值來實現 上拉或者 下拉的效果。感覺有點不流暢,而且層次嵌套得比較多。當然他的好處是擴展性好。

    因工作需求,需要層次嵌套少,對性能要求非常高。因此重新自定義了ViewGroup實現。

    Android 自定義ScrollView 支持慣性滑動,慣性回彈效果。支持上拉加載更多_android

    直接上代碼:

    1. package?com.example.administrator.customscrollview;??
    2. ??
    3. import?android.content.Context;??
    4. import?android.content.res.TypedArray;??
    5. import?android.util.AttributeSet;??
    6. import?android.util.Log;??
    7. import?android.view.Gravity;??
    8. import?android.view.MotionEvent;??
    9. import?android.view.VelocityTracker;??
    10. import?android.view.View;??
    11. import?android.view.ViewConfiguration;??
    12. import?android.view.ViewGroup;??
    13. import?android.widget.OverScroller;??
    14. ??
    15. /**?
    16. ?*?自定義?pulltorefresh?Layout?
    17. ?*?TODO:?ferris?2015年9月11日?18:52:40?
    18. ?*/??
    19. public?class?PullTorefreshScrollView?extends?ViewGroup?{??
    20. ??
    21. ????private?FoodeLayout?fooder_layout;//?top?and?buttom??
    22. ????private?View?top_layout;??
    23. ??
    24. ????private?int?desireWidth,?desireHeight;??
    25. ????private?VelocityTracker?velocityTracker;??
    26. ????private?int?mPointerId;??
    27. ????private?float?x,?y;??
    28. ????private?OverScroller?mScroller;??
    29. ????private?int?maxFlingVelocity,?minFlingVelocity;??
    30. ????private?int?mTouchSlop;??
    31. ????protected?Boolean?isMove?=?false;??
    32. ????protected?float?downX?=?0,?downY?=?0;??
    33. ????private?int?top_hight?=?0;??
    34. ????private?int?scrollYButtom?=?0;??
    35. ????private?int?nScrollYButtom?=?0;??
    36. ??
    37. ????private?int?pullDownMin?=?0;??
    38. ????private?Boolean?isEnablePullDown?=?true;??
    39. ??
    40. ????private?Boolean?isFirst=true;??
    41. ??
    42. ????public?void?setEnablePullDown(Boolean?isEnablePullDown)?{??
    43. ????????this.isEnablePullDown?=?isEnablePullDown;??
    44. ????}??
    45. ??
    46. ????public?PullTorefreshScrollView(Context?context)?{??
    47. ????????super(context);??
    48. ????????init(null,?0);??
    49. ????}??
    50. ??
    51. ????public?PullTorefreshScrollView(Context?context,?AttributeSet?attrs)?{??
    52. ????????super(context,?attrs);??
    53. ????????init(attrs,?0);??
    54. ????}??
    55. ??
    56. ????public?PullTorefreshScrollView(Context?context,?AttributeSet?attrs,?int?defStyle)?{??
    57. ????????super(context,?attrs,?defStyle);??
    58. ????????init(attrs,?defStyle);??
    59. ????}??
    60. ??
    61. ????private?void?init(AttributeSet?attrs,?int?defStyle)?{??
    62. ????????//?Load?attributes??
    63. //????????final?TypedArray?a?=?getContext().obtainStyledAttributes(??
    64. //????????????????attrs,?R.styleable.PullTorefreshScrollView,?defStyle,?0);??
    65. //??
    66. //??
    67. //????????a.recycle();??
    68. ????????mScroller?=?new?OverScroller(getContext());??
    69. ????????maxFlingVelocity?=?ViewConfiguration.get(getContext()).getScaledMaximumFlingVelocity();??
    70. ????????minFlingVelocity?=?ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();??
    71. ????????mTouchSlop?=?ViewConfiguration.get(getContext()).getScaledTouchSlop();??
    72. ????}??
    73. ??
    74. ????@Override??
    75. ????protected?void?onFinishInflate()?{??
    76. ????????super.onFinishInflate();??
    77. ????????fooder_layout?=?(FoodeLayout)?findViewById(R.id.fooder_layout);??
    78. ????????top_layout?=?findViewById(R.id.top_layout);??
    79. ??
    80. ??
    81. ????????if?(isEnablePullDown)?{??
    82. ????????????fooder_layout.showFooderPull();??
    83. ????????}?else?{??
    84. ????????????fooder_layout.hideFooder();??
    85. ????????}??
    86. ????}??
    87. ??
    88. ??
    89. ????public?int?getScrollYTop()?{??
    90. ????????return?top_hight;??
    91. ????}??
    92. ??
    93. ????public?int?getScrollYButtom()?{??
    94. ????????return?scrollYButtom;??
    95. ????}??
    96. ??
    97. ????public?int?getNScrollYTop()?{??
    98. ????????return?0;??
    99. ????}??
    100. ??
    101. ????public?int?getNScrollYButtom()?{??
    102. ????????return?nScrollYButtom;??
    103. ????}??
    104. ??
    105. ????public?int?measureWidth(int?widthMeasureSpec)?{??
    106. ????????int?result?=?0;??
    107. ????????int?measureMode?=?MeasureSpec.getMode(widthMeasureSpec);??
    108. ????????int?width?=?MeasureSpec.getSize(widthMeasureSpec);??
    109. ????????switch?(measureMode)?{??
    110. ????????????case?MeasureSpec.AT_MOST:??
    111. ????????????case?MeasureSpec.EXACTLY:??
    112. ????????????????result?=?width;??
    113. ????????????????break;??
    114. ????????????default:??
    115. ????????????????break;??
    116. ????????}??
    117. ????????return?result;??
    118. ????}??
    119. ??
    120. ????public?int?measureHeight(int?heightMeasureSpec)?{??
    121. ????????int?result?=?0;??
    122. ????????int?measureMode?=?MeasureSpec.getMode(heightMeasureSpec);??
    123. ????????int?height?=?MeasureSpec.getSize(heightMeasureSpec);??
    124. ????????switch?(measureMode)?{??
    125. ????????????case?MeasureSpec.AT_MOST:??
    126. ????????????case?MeasureSpec.EXACTLY:??
    127. ????????????????result?=?height;??
    128. ????????????????break;??
    129. ????????????default:??
    130. ????????????????break;??
    131. ????????}??
    132. ????????return?result;??
    133. ????}??
    134. ??
    135. ????@Override??
    136. ????protected?void?onMeasure(int?widthMeasureSpec,?int?heightMeasureSpec)?{??
    137. ????????//?計算所有child?view?要占用的空間??
    138. ????????int?width?=?measureWidth(widthMeasureSpec);??
    139. ????????int?height?=?measureHeight(heightMeasureSpec);??
    140. ??
    141. ????????desireWidth?=?0;??
    142. ????????desireHeight?=?0;??
    143. ????????int?count?=?getChildCount();??
    144. ????????for?(int?i?=?0;?i?<?count;?++i)?{??
    145. ????????????View?v?=?getChildAt(i);??
    146. ??
    147. ????????????if?(v.getVisibility()?!=?View.GONE)?{??
    148. ??
    149. ????????????????LayoutParams?lp?=?(LayoutParams)?v.getLayoutParams();??
    150. ????????????????measureChildWithMargins(v,?widthMeasureSpec,?0,??
    151. ????????????????????????heightMeasureSpec,?0);??
    152. ??
    153. ????????????????//只是在這里增加了垂直或者水平方向的判斷??
    154. ????????????????if?(v.getId()?==?R.id.top_layout)?{??
    155. ????????????????????top_hight?=?v.getMeasuredHeight();??
    156. ????????????????}??
    157. ????????????????desireWidth?=?Math.max(desireWidth,?v.getMeasuredWidth()??
    158. ????????????????????????+?lp.leftMargin?+?lp.rightMargin);??
    159. ????????????????desireHeight?+=?v.getMeasuredHeight()?+?lp.topMargin??
    160. ????????????????????????+?lp.bottomMargin;??
    161. ??
    162. ????????????}??
    163. ????????}??
    164. ??
    165. ????????//?count?with?padding??
    166. ????????desireWidth?+=?getPaddingLeft()?+?getPaddingRight();??
    167. ????????desireHeight?+=?getPaddingTop()?+?getPaddingBottom();??
    168. ??
    169. ????????//?see?if?the?size?is?big?enough??
    170. ????????desireWidth?=?Math.max(desireWidth,?getSuggestedMinimumWidth());??
    171. ????????desireHeight?=?Math.max(desireHeight,?getSuggestedMinimumHeight());??
    172. ??
    173. ??
    174. ????????//處理內容比較少的時候,就添加一定的高度??
    175. ????????int?scrollHight?=?height?+?top_hight?*?2;??
    176. ????????if?(scrollHight?>?desireWidth)?{??
    177. ????????????int?offset?=?scrollHight?-?desireHeight;??
    178. ????????????View?view?=?new?View(getContext());??
    179. ????????????view.setBackgroundResource(R.color.top_layout_color);??
    180. ????????????LayoutParams?lp?=?new?LayoutParams(LayoutParams.MATCH_PARENT,?offset);??
    181. ????????????addView(view,?getChildCount()?-?1,?lp);??
    182. ????????????desireWidth?=?scrollHight;??
    183. ????????}??
    184. ??
    185. ??
    186. ????????setMeasuredDimension(resolveSize(desireWidth,?widthMeasureSpec),??
    187. ????????????????resolveSize(desireHeight,?heightMeasureSpec));??
    188. ??
    189. ????????scrollYButtom?=?desireHeight?-?getMeasuredHeight()?-?top_hight;??
    190. ????????nScrollYButtom?=?desireHeight?-?getMeasuredHeight();??
    191. ????????//如果上啦拖出一半的高度,就代表將要執行上啦??
    192. ????????pullDownMin?=?nScrollYButtom?-?top_hight?/?2;??
    193. ????????if(isFirst){??
    194. ????????????scrollTo(0,?top_hight);??
    195. ????????????isFirst=false;??
    196. ????????}??
    197. ??
    198. ????}??
    199. ??
    200. ????@Override??
    201. ????protected?void?onLayout(boolean?changed,?int?l,?int?t,?int?r,?int?b)?{??
    202. ????????final?int?parentLeft?=?getPaddingLeft();??
    203. ????????final?int?parentRight?=?r?-?l?-?getPaddingRight();??
    204. ????????final?int?parentTop?=?getPaddingTop();??
    205. ????????final?int?parentBottom?=?b?-?t?-?getPaddingBottom();??
    206. ??
    207. ????????if?(BuildConfig.DEBUG)??
    208. ????????????Log.d("onlayout",?"parentleft:?"?+?parentLeft?+?"???parenttop:?"??
    209. ????????????????????+?parentTop?+?"???parentright:?"?+?parentRight??
    210. ????????????????????+?"???parentbottom:?"?+?parentBottom);??
    211. ??
    212. ????????int?left?=?parentLeft;??
    213. ????????int?top?=?parentTop;??
    214. ??
    215. ????????int?count?=?getChildCount();??
    216. ????????for?(int?i?=?0;?i?<?count;?++i)?{??
    217. ????????????View?v?=?getChildAt(i);??
    218. ????????????if?(v.getVisibility()?!=?View.GONE)?{??
    219. ????????????????LayoutParams?lp?=?(LayoutParams)?v.getLayoutParams();??
    220. ????????????????final?int?childWidth?=?v.getMeasuredWidth();??
    221. ????????????????final?int?childHeight?=?v.getMeasuredHeight();??
    222. ????????????????final?int?gravity?=?lp.gravity;??
    223. ????????????????final?int?horizontalGravity?=?gravity??
    224. ????????????????????????&?Gravity.HORIZONTAL_GRAVITY_MASK;??
    225. ????????????????final?int?verticalGravity?=?gravity??
    226. ????????????????????????&?Gravity.VERTICAL_GRAVITY_MASK;??
    227. ??
    228. ??
    229. ????????????????//?layout?vertical,?and?only?consider?horizontal?gravity??
    230. ??
    231. ????????????????left?=?parentLeft;??
    232. ????????????????top?+=?lp.topMargin;??
    233. ????????????????switch?(horizontalGravity)?{??
    234. ????????????????????case?Gravity.LEFT:??
    235. ????????????????????????break;??
    236. ????????????????????case?Gravity.CENTER_HORIZONTAL:??
    237. ????????????????????????left?=?parentLeft??
    238. ????????????????????????????????+?(parentRight?-?parentLeft?-?childWidth)?/?2??
    239. ????????????????????????????????+?lp.leftMargin?-?lp.rightMargin;??
    240. ????????????????????????break;??
    241. ????????????????????case?Gravity.RIGHT:??
    242. ????????????????????????left?=?parentRight?-?childWidth?-?lp.rightMargin;??
    243. ????????????????????????break;??
    244. ????????????????}??
    245. ????????????????v.layout(left,?top,?left?+?childWidth,?top?+?childHeight);??
    246. ????????????????top?+=?childHeight?+?lp.bottomMargin;??
    247. ????????????}??
    248. ??
    249. ????????}??
    250. ??
    251. ??
    252. ????}??
    253. ??
    254. ????@Override??
    255. ????protected?android.view.ViewGroup.LayoutParams?generateDefaultLayoutParams()?{??
    256. ????????return?new?LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,??
    257. ????????????????ViewGroup.LayoutParams.MATCH_PARENT);??
    258. ????}??
    259. ??
    260. ????@Override??
    261. ????public?android.view.ViewGroup.LayoutParams?generateLayoutParams(??
    262. ????????????AttributeSet?attrs)?{??
    263. ????????return?new?LayoutParams(getContext(),?attrs);??
    264. ????}??
    265. ??
    266. ????@Override??
    267. ????protected?android.view.ViewGroup.LayoutParams?generateLayoutParams(??
    268. ????????????android.view.ViewGroup.LayoutParams?p)?{??
    269. ????????return?new?LayoutParams(p);??
    270. ????}??
    271. ??
    272. ????public?static?class?LayoutParams?extends?MarginLayoutParams?{??
    273. ????????public?int?gravity?=?-1;??
    274. ??
    275. ????????public?LayoutParams(Context?c,?AttributeSet?attrs)?{??
    276. ????????????super(c,?attrs);??
    277. ??
    278. ????????????TypedArray?ta?=?c.obtainStyledAttributes(attrs,??
    279. ????????????????????R.styleable.SlideGroup);??
    280. ??
    281. ????????????gravity?=?ta.getInt(R.styleable.SlideGroup_layout_gravity,?-1);??
    282. ??
    283. ????????????ta.recycle();??
    284. ????????}??
    285. ??
    286. ????????public?LayoutParams(int?width,?int?height)?{??
    287. ????????????this(width,?height,?-1);??
    288. ????????}??
    289. ??
    290. ????????public?LayoutParams(int?width,?int?height,?int?gravity)?{??
    291. ????????????super(width,?height);??
    292. ????????????this.gravity?=?gravity;??
    293. ????????}??
    294. ??
    295. ????????public?LayoutParams(android.view.ViewGroup.LayoutParams?source)?{??
    296. ????????????super(source);??
    297. ????????}??
    298. ??
    299. ????????public?LayoutParams(MarginLayoutParams?source)?{??
    300. ????????????super(source);??
    301. ????????}??
    302. ????}??
    303. ??
    304. ??
    305. ????/**?
    306. ?????*?onInterceptTouchEvent()用來詢問是否要攔截處理。?onTouchEvent()是用來進行處理。?
    307. ?????*?<p/>?
    308. ?????*?例如:parentLayout----childLayout----childView?事件的分發流程:?
    309. ?????*?parentLayout::onInterceptTouchEvent()---false?--->?
    310. ?????*?childLayout::onInterceptTouchEvent()---false?--->?
    311. ?????*?childView::onTouchEvent()---false?--->?
    312. ?????*?childLayout::onTouchEvent()---false?--->?parentLayout::onTouchEvent()?
    313. ?????*?<p/>?
    314. ?????*?<p/>?
    315. ?????*?<p/>?
    316. ?????*?如果onInterceptTouchEvent()返回false,且分發的子View的onTouchEvent()中返回true,?
    317. ?????*?那么onInterceptTouchEvent()將收到所有的后續事件。?
    318. ?????*?<p/>?
    319. ?????*?如果onInterceptTouchEvent()返回true,原本的target將收到ACTION_CANCEL,該事件?
    320. ?????*?將會發送給我們自己的onTouchEvent()。?
    321. ?????*/??
    322. ????@Override??
    323. ????public?boolean?onInterceptTouchEvent(MotionEvent?ev)?{??
    324. ????????final?int?action?=?ev.getActionMasked();??
    325. ????????if?(BuildConfig.DEBUG)??
    326. ????????????Log.d("onInterceptTouchEvent",?"action:?"?+?action);??
    327. ??
    328. ????????if?(action?==?MotionEvent.ACTION_DOWN?&&?ev.getEdgeFlags()?!=?0)?{??
    329. ????????????//?該事件可能不是我們的??
    330. ????????????return?false;??
    331. ????????}??
    332. ??
    333. ????????boolean?isIntercept?=?false;??
    334. ????????switch?(action)?{??
    335. ????????????case?MotionEvent.ACTION_DOWN:??
    336. ????????????????//?如果動畫還未結束,則將此事件交給onTouchEvet()處理,??
    337. ????????????????//?否則,先分發給子View??
    338. ????????????????isIntercept?=?!mScroller.isFinished();??
    339. ????????????????//?如果此時不攔截ACTION_DOWN時間,應該記錄下觸摸地址及手指id,當我們決定攔截ACTION_MOVE的event時,??
    340. ????????????????//?將會需要這些初始信息(因為我們的onTouchEvent將可能接收不到ACTION_DOWN事件)??
    341. ????????????????mPointerId?=?ev.getPointerId(0);??
    342. //??????????if?(!isIntercept)?{??
    343. ????????????????downX?=?x?=?ev.getX();??
    344. ????????????????downY?=?y?=?ev.getY();??
    345. //??????????}??
    346. ????????????????break;??
    347. ????????????case?MotionEvent.ACTION_MOVE:??
    348. ????????????????int?pointerIndex?=?ev.findPointerIndex(mPointerId);??
    349. ????????????????if?(BuildConfig.DEBUG)??
    350. ????????????????????Log.d("onInterceptTouchEvent",?"pointerIndex:?"?+?pointerIndex??
    351. ????????????????????????????+?",?pointerId:?"?+?mPointerId);??
    352. ????????????????float?mx?=?ev.getX(pointerIndex);??
    353. ????????????????float?my?=?ev.getY(pointerIndex);??
    354. ??
    355. ????????????????if?(BuildConfig.DEBUG)??
    356. ????????????????????Log.d("onInterceptTouchEvent",?"action_move?[touchSlop:?"??
    357. ????????????????????????????+?mTouchSlop?+?",?deltaX:?"?+?(x?-?mx)?+?",?deltaY:?"??
    358. ????????????????????????????+?(y?-?my)?+?"]");??
    359. ??
    360. ????????????????//?根據方向進行攔截,(其實這樣,如果我們的方向是水平的,里面有一個ScrollView,那么我們是支持嵌套的)??
    361. ??
    362. ????????????????if?(Math.abs(y?-?my)?>=?mTouchSlop)?{??
    363. ????????????????????isIntercept?=?true;??
    364. ????????????????}??
    365. ??
    366. ??
    367. ????????????????//如果不攔截的話,我們不會更新位置,這樣可以通過累積小的移動距離來判斷是否達到可以認為是Move的閾值。??
    368. ????????????????//這里當產生攔截的話,會更新位置(這樣相當于損失了mTouchSlop的移動距離,如果不更新,可能會有一點點跳的感覺)??
    369. ????????????????if?(isIntercept)?{??
    370. ????????????????????x?=?mx;??
    371. ????????????????????y?=?my;??
    372. ????????????????}??
    373. ????????????????break;??
    374. ????????????case?MotionEvent.ACTION_CANCEL:??
    375. ????????????case?MotionEvent.ACTION_UP:??
    376. ????????????????//?這是觸摸的最后一個事件,無論如何都不會攔截??
    377. ????????????????if?(velocityTracker?!=?null)?{??
    378. ????????????????????velocityTracker.recycle();??
    379. ????????????????????velocityTracker?=?null;??
    380. ????????????????}??
    381. ????????????????break;??
    382. ????????????case?MotionEvent.ACTION_POINTER_UP:??
    383. ????????????????solvePointerUp(ev);??
    384. ??
    385. ????????????????break;??
    386. ????????}??
    387. ????????return?isIntercept;??
    388. ????}??
    389. ??
    390. ????private?void?solvePointerUp(MotionEvent?event)?{??
    391. ????????//?獲取離開屏幕的手指的索引??
    392. ????????int?pointerIndexLeave?=?event.getActionIndex();??
    393. ????????int?pointerIdLeave?=?event.getPointerId(pointerIndexLeave);??
    394. ????????if?(mPointerId?==?pointerIdLeave)?{??
    395. ????????????//?離開屏幕的正是目前的有效手指,此處需要重新調整,并且需要重置VelocityTracker??
    396. ????????????int?reIndex?=?pointerIndexLeave?==?0???1?:?0;??
    397. ????????????mPointerId?=?event.getPointerId(reIndex);??
    398. ????????????//?調整觸摸位置,防止出現跳動??
    399. ????????????x?=?event.getX(reIndex);??
    400. ????????????y?=?event.getY(reIndex);??
    401. ????????????if?(velocityTracker?!=?null)??
    402. ????????????????velocityTracker.clear();??
    403. ????????}??
    404. ????}??
    405. ??
    406. ????@Override??
    407. ????public?boolean?onTouchEvent(MotionEvent?event)?{??
    408. ??
    409. ????????final?int?action?=?event.getActionMasked();??
    410. ??
    411. ????????if?(velocityTracker?==?null)?{??
    412. ????????????velocityTracker?=?VelocityTracker.obtain();??
    413. ????????}??
    414. ????????velocityTracker.addMovement(event);??
    415. ??
    416. ????????switch?(action)?{??
    417. ????????????case?MotionEvent.ACTION_DOWN:??
    418. ????????????????//?獲取索引為0的手指id??
    419. ??
    420. ??
    421. ????????????????isMove?=?false;??
    422. ????????????????mPointerId?=?event.getPointerId(0);??
    423. ????????????????x?=?event.getX();??
    424. ????????????????y?=?event.getY();??
    425. ????????????????if?(!mScroller.isFinished())??
    426. ????????????????????mScroller.abortAnimation();??
    427. ????????????????break;??
    428. ????????????case?MotionEvent.ACTION_MOVE:??
    429. ????????????????isMove?=?true;??
    430. ????????????????//?獲取當前手指id所對應的索引,雖然在ACTION_DOWN的時候,我們默認選取索引為0??
    431. ????????????????//?的手指,但當有第二個手指觸摸,并且先前有效的手指up之后,我們會調整有效手指??
    432. ??
    433. ????????????????//?屏幕上可能有多個手指,我們需要保證使用的是同一個手指的移動軌跡,??
    434. ????????????????//?因此此處不能使用event.getActionIndex()來獲得索引??
    435. ????????????????final?int?pointerIndex?=?event.findPointerIndex(mPointerId);??
    436. ????????????????float?mx?=?event.getX(pointerIndex);??
    437. ????????????????float?my?=?event.getY(pointerIndex);??
    438. ??
    439. ????????????????moveBy((int)?(x?-?mx),?(int)?(y?-?my));??
    440. ??
    441. ????????????????x?=?mx;??
    442. ????????????????y?=?my;??
    443. ????????????????break;??
    444. ????????????case?MotionEvent.ACTION_UP:??
    445. ????????????????isMove?=?false;??
    446. ????????????????velocityTracker.computeCurrentVelocity(1000,?maxFlingVelocity);??
    447. ????????????????float?velocityX?=?velocityTracker.getXVelocity(mPointerId);??
    448. ????????????????float?velocityY?=?velocityTracker.getYVelocity(mPointerId);??
    449. ??
    450. ????????????????completeMove(-velocityX,?-velocityY);??
    451. ????????????????if?(velocityTracker?!=?null)?{??
    452. ????????????????????velocityTracker.recycle();??
    453. ????????????????????velocityTracker?=?null;??
    454. ????????????????}??
    455. ????????????????break;??
    456. ??
    457. ????????????case?MotionEvent.ACTION_POINTER_UP:??
    458. ????????????????//?獲取離開屏幕的手指的索引??
    459. ????????????????isMove?=?false;??
    460. ????????????????int?pointerIndexLeave?=?event.getActionIndex();??
    461. ????????????????int?pointerIdLeave?=?event.getPointerId(pointerIndexLeave);??
    462. ????????????????if?(mPointerId?==?pointerIdLeave)?{??
    463. ????????????????????//?離開屏幕的正是目前的有效手指,此處需要重新調整,并且需要重置VelocityTracker??
    464. ????????????????????int?reIndex?=?pointerIndexLeave?==?0???1?:?0;??
    465. ????????????????????mPointerId?=?event.getPointerId(reIndex);??
    466. ????????????????????//?調整觸摸位置,防止出現跳動??
    467. ????????????????????x?=?event.getX(reIndex);??
    468. ????????????????????y?=?event.getY(reIndex);??
    469. ????????????????????if?(velocityTracker?!=?null)??
    470. ????????????????????????velocityTracker.clear();??
    471. ????????????????}??
    472. ????????????????break;??
    473. ????????????case?MotionEvent.ACTION_CANCEL:??
    474. ????????????????isMove?=?false;??
    475. ????????????????break;??
    476. ????????}??
    477. ????????return?true;??
    478. ????}??
    479. ??
    480. ????private?Boolean?isPull?=?false;??
    481. ??
    482. ????//此處的moveBy是根據水平或是垂直排放的方向,??
    483. //來選擇是水平移動還是垂直移動??
    484. ????public?void?moveBy(int?deltaX,?int?deltaY)?{??
    485. ????????if?(BuildConfig.DEBUG)??
    486. ????????????Log.d("moveBy",?"deltaX:?"?+?deltaX?+?"????deltaY:?"?+?deltaY);??
    487. ????????if?(Math.abs(deltaY)?>=?Math.abs(deltaX))?{??
    488. ????????????int?mScrollY?=?getScrollY();??
    489. ????????????if?(mScrollY?<=?0)?{??
    490. ????????????????scrollTo(0,?0);??
    491. ????????????}?else?if?(mScrollY?>=?getNScrollYButtom())?{??
    492. ????????????????scrollTo(0,?getNScrollYButtom());??
    493. ??
    494. ??
    495. ????????????}?else?{??
    496. ????????????????scrollBy(0,?deltaY);??
    497. ????????????}??
    498. ??
    499. ????????????if?(isEnablePullDown?&&?deltaY?>?0?&&?mScrollY?>=?pullDownMin)?{??
    500. ????????????????isPull?=?true;??
    501. ????????????????Log.d("onlayout",?"isPull:?true");??
    502. ????????????}??
    503. ????????}??
    504. ??
    505. ??
    506. ????}??
    507. ??
    508. ????private?void?completeMove(float?velocityX,?float?velocityY)?{??
    509. ??
    510. ????????int?mScrollY?=?getScrollY();??
    511. ????????int?maxY?=?getScrollYButtom();??
    512. ????????int?minY?=?getScrollYTop();??
    513. ??
    514. ??
    515. ????????if?(mScrollY?>=?maxY)?{//如果滾動,超過了?下邊界,就回彈到下邊界??
    516. ??
    517. ????????????if?(isPull)?{//滾動到最底部??
    518. ????????????????mScroller.startScroll(0,?mScrollY,?0,?getNScrollYButtom()?-?mScrollY,?300);??
    519. ????????????????invalidate();??
    520. ??
    521. ????????????????//顯示雷達??
    522. ????????????????fooder_layout.showFooderRadar();??
    523. ????????????????if?(pullDownListem?!=?null)?{??
    524. ????????????????????pullDownListem.onPullDown();??
    525. ????????????????}??
    526. ????????????????Log.d("onlayout",?"isPull:?true?滾動到最底部,顯示出雷達");??
    527. ??
    528. ????????????}?else?{??
    529. ????????????????mScroller.startScroll(0,?mScrollY,?0,?maxY?-?mScrollY);??
    530. ????????????????invalidate();??
    531. ????????????????Log.d("onlayout",?"isPull:?true");??
    532. ????????????}??
    533. ??
    534. ????????}?else?if?(mScrollY?<=?minY)?{//如果滾動,超過了上邊界,就回彈到上邊界??
    535. ????????????//?超出了上邊界,彈回??
    536. ????????????mScroller.startScroll(0,?mScrollY,?0,?minY?-?mScrollY);??
    537. ????????????invalidate();??
    538. ????????}?else?if?(Math.abs(velocityY)?>=?minFlingVelocity?&&?maxY?>?0)?{//大于1頁的時候??
    539. //????????????mScroller.fling(0,?mScrollY,?0,?(int)?(velocityY?*?1.2f),?0,?0,?minY,?maxY);??
    540. ????????????mScroller.fling(0,?mScrollY,?0,?(int)?(velocityY?*?2f),?0,?0,?getNScrollYTop(),?getNScrollYButtom());??
    541. ????????????invalidate();??
    542. ????????}??
    543. ??
    544. ??
    545. ????}??
    546. ??
    547. ??
    548. ????public?void?ifNeedScrollBack()?{??
    549. ????????int?mScrollY?=?getScrollY();??
    550. ????????int?maxY?=?getScrollYButtom();??
    551. ????????int?minY?=?getScrollYTop();??
    552. ????????if?(mScrollY?>?maxY)?{??
    553. ????????????//?超出了下邊界,彈回??
    554. ????????????mScroller.startScroll(0,?mScrollY,?0,?maxY?-?mScrollY);??
    555. ??
    556. ????????????invalidate();??
    557. ??
    558. ????????}?else?if?(mScrollY?<?minY)?{??
    559. ????????????//?超出了上邊界,彈回??
    560. ????????????mScroller.startScroll(0,?mScrollY,?0,?minY?-?mScrollY);??
    561. ????????????invalidate();??
    562. ????????}??
    563. ????}??
    564. ??
    565. ????@Override??
    566. ????protected?void?onScrollChanged(int?l,?int?t,?int?oldl,?int?oldt)?{??
    567. ????????super.onScrollChanged(l,?t,?oldl,?oldt);??
    568. ????}??
    569. ??
    570. ????@Override??
    571. ????public?void?computeScroll()?{??
    572. ????????if?(mScroller.computeScrollOffset())?{??
    573. ??
    574. ????????????scrollTo(0,?mScroller.getCurrY());??
    575. ??
    576. ????????????postInvalidate();??
    577. ??
    578. ????????}?else?{??
    579. ????????????Log.d("onlayout",?"computeScroll,isMove:"+isMove+",isPull:"+isPull);??
    580. ????????????if?(!isMove?&&?!isPull)?{??
    581. ????????????????ifNeedScrollBack();??
    582. ????????????}??
    583. ??
    584. ????????}??
    585. ????}??
    586. ??
    587. ??
    588. ????public?void?onPullSuccess()?{??
    589. ??
    590. ????????soomToBack();??
    591. ????}??
    592. ??
    593. ????public?void?soomToBack()?{??
    594. ????????int?mScrollY?=?getScrollY();??
    595. ????????int?maxY?=?getScrollYButtom();??
    596. ????????Log.d("onlayout",?"soomToBack:?(maxY?-?mScrollY)="+(maxY?-?mScrollY)+",maxY="+maxY+",mScrollY="+mScrollY);??
    597. ????????//?超出了下邊界,彈回??
    598. ????????mScroller.startScroll(0,?mScrollY,?0,?maxY?-?mScrollY,?300);??
    599. ????????invalidate();??
    600. ????????postDelayed(new?Runnable()?{??
    601. ????????????@Override??
    602. ????????????public?void?run()?{??
    603. ????????????????fooder_layout.showFooderPull();??
    604. ????????????????isPull?=?false;??
    605. ????????????}??
    606. ????????},?310);??
    607. ??
    608. ??
    609. ????}??
    610. ??
    611. ????private?PullDownListem?pullDownListem;??
    612. ??
    613. ????public?void?setPullDownListem(PullDownListem?pullDownListem)?{??
    614. ????????this.pullDownListem?=?pullDownListem;??
    615. ????}??
    616. ??
    617. ????public?interface?PullDownListem?{??
    618. ??
    619. ????????public?void?onPullDown();??
    620. ??
    621. ????}??
    622. }?

    本文摘自 :https://blog.51cto.com/u

    開通會員,享受整站包年服務
    国产呦精品一区二区三区网站|久久www免费人咸|精品无码人妻一区二区|久99久热只有精品国产15|中文字幕亚洲无线码