當(dāng)前位置:首頁 > IT技術(shù) > 移動平臺 > 正文

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

先講下原理:

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

我們實(shí)現(xiàn)慣性滑動,以及回彈,都是靠超過head或者fooder 就重新滾動到? ,內(nèi)容的頂部或者底部。

之前看了Pulltorefresh 他是通過不斷改變 head或者 fooder的 pading 值來實(shí)現(xiàn) 上拉或者 下拉的效果。感覺有點(diǎn)不流暢,而且層次嵌套得比較多。當(dāng)然他的好處是擴(kuò)展性好。

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

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. ????????//處理內(nèi)容比較少的時候,就添加一定的高度??
  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. ????????//如果上啦拖出一半的高度,就代表將要執(zhí)行上啦??
  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()是用來進(jìn)行處理。?
  307. ?????*?<p/>?
  308. ?????*?例如:parentLayout----childLayout----childView?事件的分發(fā)流程:?
  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,且分發(fā)的子View的onTouchEvent()中返回true,?
  317. ?????*?那么onInterceptTouchEvent()將收到所有的后續(xù)事件。?
  318. ?????*?<p/>?
  319. ?????*?如果onInterceptTouchEvent()返回true,原本的target將收到ACTION_CANCEL,該事件?
  320. ?????*?將會發(fā)送給我們自己的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. ????????????????//?如果動畫還未結(jié)束,則將此事件交給onTouchEvet()處理,??
  337. ????????????????//?否則,先分發(fā)給子View??
  338. ????????????????isIntercept?=?!mScroller.isFinished();??
  339. ????????????????//?如果此時不攔截ACTION_DOWN時間,應(yīng)該記錄下觸摸地址及手指id,當(dāng)我們決定攔截ACTION_MOVE的event時,??
  340. ????????????????//?將會需要這些初始信息(因?yàn)槲覀兊膐nTouchEvent將可能接收不到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. ????????????????//?根據(jù)方向進(jìn)行攔截,(其實(shí)這樣,如果我們的方向是水平的,里面有一個ScrollView,那么我們是支持嵌套的)??
  361. ??
  362. ????????????????if?(Math.abs(y?-?my)?>=?mTouchSlop)?{??
  363. ????????????????????isIntercept?=?true;??
  364. ????????????????}??
  365. ??
  366. ??
  367. ????????????????//如果不攔截的話,我們不會更新位置,這樣可以通過累積小的移動距離來判斷是否達(dá)到可以認(rèn)為是Move的閾值。??
  368. ????????????????//這里當(dāng)產(chǎn)生攔截的話,會更新位置(這樣相當(dāng)于損失了mTouchSlop的移動距離,如果不更新,可能會有一點(diǎn)點(diǎn)跳的感覺)??
  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. ????????????//?離開屏幕的正是目前的有效手指,此處需要重新調(diào)整,并且需要重置VelocityTracker??
  396. ????????????int?reIndex?=?pointerIndexLeave?==?0???1?:?0;??
  397. ????????????mPointerId?=?event.getPointerId(reIndex);??
  398. ????????????//?調(diào)整觸摸位置,防止出現(xiàn)跳動??
  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. ????????????????//?獲取當(dāng)前手指id所對應(yīng)的索引,雖然在ACTION_DOWN的時候,我們默認(rèn)選取索引為0??
  431. ????????????????//?的手指,但當(dāng)有第二個手指觸摸,并且先前有效的手指up之后,我們會調(diào)整有效手指??
  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. ????????????????????//?離開屏幕的正是目前的有效手指,此處需要重新調(diào)整,并且需要重置VelocityTracker??
  464. ????????????????????int?reIndex?=?pointerIndexLeave?==?0???1?:?0;??
  465. ????????????????????mPointerId?=?event.getPointerId(reIndex);??
  466. ????????????????????//?調(diào)整觸摸位置,防止出現(xiàn)跳動??
  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是根據(jù)水平或是垂直排放的方向,??
  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. ????????????????//顯示雷達(dá)??
  522. ????????????????fooder_layout.showFooderRadar();??
  523. ????????????????if?(pullDownListem?!=?null)?{??
  524. ????????????????????pullDownListem.onPullDown();??
  525. ????????????????}??
  526. ????????????????Log.d("onlayout",?"isPull:?true?滾動到最底部,顯示出雷達(dá)");??
  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

開通會員,享受整站包年服務(wù)立即開通 >