Android中listView的底部拖拉翻页的实现,这份字节跳动历年校招Android面试真题解析

这篇文章详细描述了一个自定义的PullToRefreshListView组件,包括设置滚动监听器、刷新回调、状态管理和触控事件处理,以及刷新过程中的动画和状态转换。
摘要由CSDN通过智能技术生成
  1. *

  2. * @param l The scroll listener.

  3. */

  4. @Override

  5. public void setOnScrollListener(AbsListView.OnScrollListener l) {

  6. mOnScrollListener = l;

  7. }

  8. /**

  9. * Register a callback to be invoked when this list should be refreshed.

  10. *

  11. * @param onRefreshListener The callback to run.

  12. */

  13. public void setOnRefreshListener(OnRefreshListener onRefreshListener) {

  14. mOnRefreshListener = onRefreshListener;

  15. }

  16. /**

  17. * Set a text to represent when the list was last updated.

  18. * @param lastUpdated Last updated at.

  19. */

  20. public void setLastUpdated(CharSequence lastUpdated) {

  21. if (lastUpdated != null) {

  22. mRefreshViewLastUpdated.setVisibility(View.VISIBLE);

  23. mRefreshViewLastUpdated.setText(lastUpdated);

  24. } else {

  25. mRefreshViewLastUpdated.setVisibility(View.GONE);

  26. }

  27. }

  28. @Override

  29. public boolean onTouchEvent(MotionEvent event) {

  30. final int y = (int) event.getY();

  31. Log.i(“PullToRefreshListView”, “Height:” + getMeasuredHeight());

  32. Log.i(“PullToRefreshListView”, “MotionEvent:” + event.getAction());

  33. Log.i(“PullToRefreshListView”, “mRefreshState:” + mRefreshState);

  34. Log.i(“PullToRefreshListView”, “FirstVisiblePosition:” + getFirstVisiblePosition());

  35. Log.i(“PullToRefreshListView”, “LastVisiblePosition:” + getLastVisiblePosition());

  36. Log.i(“PullToRefreshListView”, “ChildCount:” + getAdapter().getCount());

  37. Log.i(“PullToRefreshListView”, “RefreshViewBottom:” + mRefreshView.getBottom());

  38. Log.i(“PullToRefreshListView”, “RefreshViewTop:” + mRefreshView.getTop());

  39. Log.i(“PullToRefreshListView”, “mRefreshViewHeight:” + mRefreshViewHeight);

  40. Log.i(“PullToRefreshListView”, "  ");

  41. Log.i(“PullToRefreshListView”, "  ");

  42. Log.i(“PullToRefreshListView”, "  ");

  43. switch (event.getAction()) {

  44. case MotionEvent.ACTION_UP:

  45. if (!isVerticalScrollBarEnabled()) {

  46. setVerticalScrollBarEnabled(true);

  47. }

  48. if (getLastVisiblePosition() == getAdapter().getCount() - 1

  49. && mRefreshState != REFRESHING) {

  50. if ((

  51. mRefreshView.getTop() <= getMeasuredHeight() - mRefreshViewHeight)

  52. && mRefreshState == RELEASE_TO_REFRESH) {

  53. //                        Log.i(“PullToRefreshListView”, “Fire…”);

  54. //                        Log.i(“PullToRefreshListView”, "  ");

  55. //                        Log.i(“PullToRefreshListView”, "  ");

  56. //                        Log.i(“PullToRefreshListView”, "  ");

  57. // Initiate the refresh

  58. mRefreshState = REFRESHING;

  59. prepareForRefresh();

  60. onRefresh();

  61. } else if (

  62. mRefreshView.getTop() > getMeasuredHeight() - mRefreshViewHeight) {

  63. // Abort refresh and scroll down below the refresh view

  64. resetHeader();

  65. //setSelection(1);

  66. //                        Log.v(“PPMacbook”, “pi:” + (getSelectedItemPosition() - 1));

  67. //                        setSelectionAfterHeaderView();

  68. //                        setSelection(getSelectedItemPosition() - 1);

  69. //                        System.out.println(“PPMacbook:” + (getFirstVisiblePosition() - 1));

  70. setSelection((getFirstVisiblePosition() - 1));

  71. }

  72. }

  73. break;

  74. case MotionEvent.ACTION_DOWN:

  75. mLastMotionY = y;

  76. break;

  77. case MotionEvent.ACTION_MOVE:

  78. applyHeaderPadding(event);

  79. break;

  80. }

  81. return super.onTouchEvent(event);

  82. }

  83. private void applyHeaderPadding(MotionEvent ev) {

  84. final int historySize = ev.getHistorySize();

  85. // Workaround for getPointerCount() which is unavailable in 1.5

  86. // (it’s always 1 in 1.5)

  87. int pointerCount = 1;

  88. try {

  89. Method method = MotionEvent.class.getMethod(“getPointerCount”);

  90. pointerCount = (Integer)method.invoke(ev);

  91. } catch (NoSuchMethodException e) {

  92. pointerCount = 1;

  93. } catch (IllegalArgumentException e) {

  94. throw e;

  95. } catch (IllegalAccessException e) {

  96. System.err.println("unexpected " + e);

  97. } catch (InvocationTargetException e) {

  98. System.err.println("unexpected " + e);

  99. }

  100. //        Log.i(“PullToRefreshListView”, “historySize:” + historySize);

  101. //        Log.i(“PullToRefreshListView”, “pointerCount:” + pointerCount);

  102. //        Log.i(“PullToRefreshListView”, "  ");

  103. //        Log.i(“PullToRefreshListView”, "  ");

  104. //        Log.i(“PullToRefreshListView”, "  ");

  105. for (int h = 0; h < historySize; h++) {

  106. for (int p = 0; p < pointerCount; p++) {

  107. if (mRefreshState == RELEASE_TO_REFRESH) {

  108. if (isVerticalFadingEdgeEnabled()) {

  109. setVerticalScrollBarEnabled(false);

  110. }

  111. int historicalY = 0;

  112. try {

  113. // For Android > 2.0

  114. Method method = MotionEvent.class.getMethod(

  115. “getHistoricalY”, Integer.TYPE, Integer.TYPE);

  116. historicalY = ((Float) method.invoke(ev, p, h)).intValue();

  117. } catch (NoSuchMethodException e) {

  118. // For Android < 2.0

  119. historicalY = (int) (ev.getHistoricalY(h));

  120. } catch (IllegalArgumentException e) {

  121. throw e;

  122. } catch (IllegalAccessException e) {

  123. System.err.println("unexpected " + e);

  124. } catch (InvocationTargetException e) {

  125. System.err.println("unexpected " + e);

  126. }

  127. // Calculate the padding to apply, we divide by 1.7 to

  128. // simulate a more resistant effect during pull.

  129. int topPadding = (int) (((historicalY + mLastMotionY)

  130. + mRefreshViewHeight) / 1.7);

  131. mRefreshView.setPadding(

  132. mRefreshView.getPaddingLeft(),

  133. mRefreshView.getPaddingTop(),

  134. mRefreshView.getPaddingRight(),

  135. topPadding);

  136. }

  137. }

  138. }

  139. }

  140. /**

  141. * Sets the header padding back to original size.

  142. */

  143. private void resetHeaderPadding() {

  144. mRefreshView.setPadding(

  145. mRefreshView.getPaddingLeft(),

  146. mRefreshView.getPaddingTop(),

  147. mRefreshView.getPaddingRight(),

  148. mRefreshOriginalBottomPadding);

  149. }

  150. /**

  151. * Resets the header to the original state.

  152. */

  153. private void resetHeader() {

  154. if (mRefreshState != TAP_TO_REFRESH) {

  155. mRefreshState = TAP_TO_REFRESH;

  156. resetHeaderPadding();

  157. // Set refresh view text to the pull label

  158. mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);

  159. // Replace refresh drawable with arrow drawable

  160. mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);

  161. // Clear the full rotation animation

  162. mRefreshViewImage.clearAnimation();

  163. // Hide progress bar and arrow.

  164. mRefreshViewImage.setVisibility(View.GONE);

  165. mRefreshViewProgress.setVisibility(View.GONE);

  166. }

  167. }

  168. private void measureView(View child) {

  169. ViewGroup.LayoutParams p = child.getLayoutParams();

  170. if (p == null) {

  171. p = new ViewGroup.LayoutParams(

  172. ViewGroup.LayoutParams.FILL_PARENT,

  173. ViewGroup.LayoutParams.WRAP_CONTENT);

  174. }

  175. int childWidthSpec = ViewGroup.getChildMeasureSpec(0,

  176. 0 + 0, p.width);

  177. int lpHeight = p.height;

  178. int childHeightSpec;

  179. if (lpHeight > 0) {

  180. childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);

  181. } else {

  182. childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

  183. }

  184. child.measure(childWidthSpec, childHeightSpec);

  185. }

  186. @Override

  187. public void onScroll(AbsListView view, int firstVisibleItem,

  188. int visibleItemCount, int totalItemCount) {

  189. //        Log.i(“PullToRefreshListView”, “firstVisibleItem:” + firstVisibleItem);

  190. //        Log.i(“PullToRefreshListView”, “visibleItemCount:” + visibleItemCount);

  191. //        Log.i(“PullToRefreshListView”, “totalItemCount:” + totalItemCount);

  192. //        Log.i(“PullToRefreshListView”, “”);

  193. //        Log.i(“PullToRefreshListView”, “”);

  194. //        Log.i(“PullToRefreshListView”, “”);

  195. // When the refresh view is completely visible, change the text to say

  196. // “Release to refresh…” and flip the arrow drawable.

  197. if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL

  198. && mRefreshState != REFRESHING) {

  199. if (firstVisibleItem + visibleItemCount == totalItemCount) {

  200. mRefreshViewImage.setVisibility(View.VISIBLE);

  201. if ((

  202. mRefreshView.getTop() <= getMeasuredHeight() - mRefreshViewHeight)

  203. && mRefreshState != RELEASE_TO_REFRESH) {

  204. mRefreshViewText.setText(R.string.pull_to_refresh_release_label);

  205. mRefreshViewImage.clearAnimation();

  206. mRefreshViewImage.startAnimation(mFlipAnimation);

  207. mRefreshState = RELEASE_TO_REFRESH;

  208. } else if (

  209. mRefreshView.getTop() >getMeasuredHeight() - 20 - mRefreshViewHeight

  210. && mRefreshState != PULL_TO_REFRESH) {

  211. mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);

  212. if (mRefreshState != TAP_TO_REFRESH) {

  213. mRefreshViewImage.clearAnimation();

  214. mRefreshViewImage.startAnimation(mReverseFlipAnimation);

  215. }

  216. mRefreshState = PULL_TO_REFRESH;

  217. }

  218. } else {

  219. mRefreshViewImage.setVisibility(View.GONE);

  220. resetHeader();

  221. }

  222. } else if (mCurrentScrollState == SCROLL_STATE_FLING

  223. && firstVisibleItem + visibleItemCount == totalItemCount

  224. && mRefreshState != REFRESHING) {

  225. //setSelection(1);

  226. //            Log.i(“PullToRefreshListView”, “Selection:” + (totalItemCount - visibleItemCount));

  227. setSelection(getSelectedItemPosition() - 2);

  228. //

  229. setSelection((getFirstVisiblePosition() - 1));

  230. }

  231. if (mOnScrollListener != null) {

  232. mOnScrollListener.onScroll(view, firstVisibleItem,

  233. visibleItemCount, totalItemCount);

  234. }

  235. }

  236. @Override

  237. public void onScrollStateChanged(AbsListView view, int scrollState) {

  238. mCurrentScrollState = scrollState;

  239. if (mOnScrollListener != null) {

  240. mOnScrollListener.onScrollStateChanged(view, scrollState);

  241. }

  242. }

  243. public void prepareForRefresh() {

  244. resetHeaderPadding();

  245. mRefreshViewImage.setVisibility(View.GONE);

  246. // We need this hack, otherwise it will keep the previous drawable.

  247. mRefreshViewImage.setImageDrawable(null);

  248. mRefreshViewProgress.setVisibility(View.VISIBLE);

  249. // Set refresh view text to the refreshing label

  250. mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);

  251. mRefreshState = REFRESHING;

  252. }

  253. public void onRefresh() {

  254. Log.d(TAG, “onRefresh”);

  255. if (mOnRefreshListener != null) {

  256. mOnRefreshListener.onRefresh();

  257. }

  258. }

  259. /**

  260. * Resets the list to a normal state after a refresh.

  261. * @param lastUpdated Last updated at.

  262. */

  263. public void onRefreshComplete(CharSequence lastUpdated) {

  264. setLastUpdated(lastUpdated);

  265. onRefreshComplete();

  266. }

  267. /**

  268. * Resets the list to a normal state after a refresh.

  269. */

  270. public void onRefreshComplete() {

  271. Log.d(TAG, “onRefreshComplete”);

  272. resetHeader();

  273. // If refresh view is visible when loading completes, scroll down to

  274. // the next item.

  275. if (mRefreshView.getBottom() > 0) {

  276. invalidateViews();

  277. //setSelection(1);

  278. }

  279. }

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

文末

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家

这里笔者分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

【视频教程】

天道酬勤,只要你想,大厂offer并不是遥不可及!希望本篇文章能为你带来帮助,如果有问题,请在评论区留言。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

,并且会持续更新!**

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

文末

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家

这里笔者分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

[外链图片转存中…(img-nBTonf92-1712375905495)]

[外链图片转存中…(img-4yqHPlMV-1712375905495)]

【视频教程】

[外链图片转存中…(img-Zz9lSrP3-1712375905495)]

天道酬勤,只要你想,大厂offer并不是遥不可及!希望本篇文章能为你带来帮助,如果有问题,请在评论区留言。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 25
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值