Android UI

您所在的位置:网站首页 修改安卓ui Android UI

Android UI

2023-05-12 04:25| 来源: 网络整理| 查看: 265

Android UI--自定义ListView(实现下拉刷新+加载更多)

关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆。不过我就没发现比较实用的,要不就是实现起来太复杂,要不就是不健全的。因为小巫近期要开发新浪微博客户端,需要实现ListView的下拉刷新,所以就想把这个UI整合到项目当中去,这里只是一个demo,可以根据项目的需要进行修改。

就不要太在乎界面了哈 :

Android UI--自定义ListView(实现下拉刷新+加载更多)_PullToRefreshListVie

Android UI--自定义ListView(实现下拉刷新+加载更多)_PullToRefreshListVie_02

Android UI--自定义ListView(实现下拉刷新+加载更多)_android_03

Android UI--自定义ListView(实现下拉刷新+加载更多)_android_04

Android UI--自定义ListView(实现下拉刷新+加载更多)_加载更多_05

Android UI--自定义ListView(实现下拉刷新+加载更多)_加载更多_06

知道你们想要源码了,去下吧:javascript:void(0)

自定义ListView:

[java] 

1. package com.markupartist.android.widget; 2. 3. 4. import java.lang.reflect.InvocationTargetException; 5. import java.lang.reflect.Method; 6. 7. import com.markupartist.android.example.pulltorefresh.R; 8. 9. import android.content.Context; 10. import android.util.AttributeSet; 11. import android.util.Log; 12. import android.view.LayoutInflater; 13. import android.view.MotionEvent; 14. import android.view.View; 15. import android.view.ViewGroup; 16. import android.view.animation.LinearInterpolator; 17. import android.view.animation.RotateAnimation; 18. import android.widget.AbsListView; 19. import android.widget.AbsListView.OnScrollListener; 20. import android.widget.ImageView; 21. import android.widget.ListAdapter; 22. import android.widget.ListView; 23. import android.widget.ProgressBar; 24. import android.widget.RelativeLayout; 25. import android.widget.TextView; 26. 27. 28. 29. /** 30. * 2013/8/13 31. * 自定义ListView,实现OnScrollListener接口 32. * 此ListView是为实现"下拉刷新"和"上拉加载更多"而定制的,具体效果可参考新浪微博、腾讯微博 33. * @author wwj 34. * 35. */ 36. public class PullToRefreshListView extends ListView implements OnScrollListener { 37. 38. private static final int TAP_TO_REFRESH = 1; //(未刷新) 39. private static final int PULL_TO_REFRESH = 2; // 下拉刷新 40. private static final int RELEASE_TO_REFRESH = 3; // 释放刷新 41. private static final int REFRESHING = 4; // 正在刷新 42. private static final int TAP_TO_LOADMORE = 5; // 未加载更多 43. private static final int LOADING = 6; // 正在加载 44. 45. 46. private static final String TAG = "PullToRefreshListView"; 47. 48. private OnRefreshListener mOnRefreshListener; // 刷新监听器 49. 50. /** 51. * Listener that will receive notifications every time the list scrolls. 52. */ 53. private OnScrollListener mOnScrollListener; // 列表滚动监听器 54. private LayoutInflater mInflater; // 用于加载布局文件 55. 56. private RelativeLayout mRefreshHeaderView; // 刷新视图(也就是头部那部分) 57. private TextView mRefreshViewText; // 刷新提示文本 58. private ImageView mRefreshViewImage; // 刷新向上向下的那个图片 59. private ProgressBar mRefreshViewProgress; // 这里是圆形进度条 60. private TextView mRefreshViewLastUpdated; // 最近更新的文本 61. 62. private RelativeLayout mLoadMoreFooterView; // 加载更多 63. private TextView mLoadMoreText; // 提示文本 64. private ProgressBar mLoadMoreProgress; // 加载更多进度条 65. 66. 67. private int mCurrentScrollState; // 当前滚动位置 68. private int mRefreshState; // 刷新状态 69. private int mLoadState; // 加载状态 70. 71. private RotateAnimation mFlipAnimation; // 下拉动画 72. private RotateAnimation mReverseFlipAnimation; // 恢复动画 73. 74. private int mRefreshViewHeight; // 刷新视图高度 75. private int mRefreshOriginalTopPadding; // 原始上部间隙 76. private int mLastMotionY; // 记录点击位置 77. 78. public PullToRefreshListView(Context context) { 79. super(context); 80. init(context); 81. } 82. 83. public PullToRefreshListView(Context context, AttributeSet attrs) { 84. super(context, attrs); 85. init(context); 86. } 87. 88. public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) { 89. super(context, attrs, defStyle); 90. init(context); 91. } 92. 93. private void init(Context context) { 94. // Load all of the animations we need in code rather than through XML 95. /** 定义旋转动画**/ 96. // 参数:1.旋转开始的角度 2.旋转结束的角度 3. X轴伸缩模式 4.X坐标的伸缩值 5.Y轴的伸缩模式 6.Y坐标的伸缩值 97. new RotateAnimation(0, -180, 98. 0.5f, 99. 0.5f); 100. new LinearInterpolator()); 101. 250); // 设置持续时间 102. true); // 动画执行完是否停留在执行完的状态 103. new RotateAnimation(-180, 0, 104. 0.5f, 105. 0.5f); 106. new LinearInterpolator()); 107. 250); 108. true); 109. 110. // 获取LayoutInflater实例对象 111. mInflater = (LayoutInflater) context.getSystemService( 112. Context.LAYOUT_INFLATER_SERVICE); 113. 114. // 加载下拉刷新的头部视图 115. mRefreshHeaderView = (RelativeLayout) mInflater.inflate( 116. this, false); 117. mRefreshViewText = 118. (TextView) mRefreshHeaderView.findViewById(R.id.pull_to_refresh_text); 119. mRefreshViewImage = 120. (ImageView) mRefreshHeaderView.findViewById(R.id.pull_to_refresh_image); 121. mRefreshViewProgress = 122. (ProgressBar) mRefreshHeaderView.findViewById(R.id.pull_to_refresh_progress); 123. mRefreshViewLastUpdated = 124. (TextView) mRefreshHeaderView.findViewById(R.id.pull_to_refresh_updated_at); 125. mLoadMoreFooterView = (RelativeLayout) mInflater.inflate( 126. this, false); 127. mLoadMoreText = (TextView) mLoadMoreFooterView.findViewById(R.id.loadmore_text); 128. mLoadMoreProgress = (ProgressBar) mLoadMoreFooterView.findViewById(R.id.loadmore_progress); 129. 130. 131. 50); // 设置图片最小高度 132. new OnClickRefreshListener()); 133. mRefreshOriginalTopPadding = mRefreshHeaderView.getPaddingTop(); 134. new OnClickLoadMoreListener()); 135. 136. // 初始刷新状态 137. mLoadState = TAP_TO_LOADMORE; 138. 139. // 增加头部视图 140. // 增加尾部视图 141. 142. super.setOnScrollListener(this); 143. 144. // 测量视图 145. // 得到视图的高度 146. } 147. 148. @Override 149. protected void onAttachedToWindow() { 150. 1); // 设置当前选中的项 151. } 152. 153. @Override 154. public void setAdapter(ListAdapter adapter) { 155. super.setAdapter(adapter); 156. 157. 1); 158. } 159. 160. /** 161. * Set the listener that will receive notifications every time the list 162. * scrolls. 163. * 164. * @param l The scroll listener. 165. */ 166. @Override 167. public void setOnScrollListener(AbsListView.OnScrollListener l) { 168. mOnScrollListener = l; 169. } 170. 171. /** 172. * Register a callback to be invoked when this list should be refreshed. 173. * 注册监听器 174. * @param onRefreshListener The callback to run. 175. */ 176. public void setOnRefreshListener(OnRefreshListener onRefreshListener) { 177. mOnRefreshListener = onRefreshListener; 178. } 179. 180. /** 181. * Set a text to represent when the list was last updated. 182. * 设置一个文本来表示最近更新的列表,显示的是最近更新列表的时间 183. * @param lastUpdated Last updated at. 184. */ 185. public void setLastUpdated(CharSequence lastUpdated) { 186. if (lastUpdated != null) { 187. mRefreshViewLastUpdated.setVisibility(View.VISIBLE); 188. "更新于: " + lastUpdated); 189. else { 190. mRefreshViewLastUpdated.setVisibility(View.GONE); 191. } 192. } 193. 194. @Override 195. public boolean onTouchEvent(MotionEvent event) { 196. final int y = (int) event.getY(); // 获取点击位置的Y坐标 197. 198. switch (event.getAction()) { 199. case MotionEvent.ACTION_UP: // 手指抬起 200. if (!isVerticalScrollBarEnabled()) { 201. true); 202. } 203. if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) { 204. if ((mRefreshHeaderView.getBottom() > mRefreshViewHeight 205. 0) 206. && mRefreshState == RELEASE_TO_REFRESH) { 207. // Initiate the refresh 208. // 刷新状态 209. prepareForRefresh(); 210. onRefresh(); 211. else if (mRefreshHeaderView.getBottom() < mRefreshViewHeight 212. 0) { 213. // Abort refresh and scroll down below the refresh view 214. resetHeader(); 215. 1); 216. } 217. } 218. break; 219. case MotionEvent.ACTION_DOWN: 220. mLastMotionY = y; 221. break; 222. case MotionEvent.ACTION_MOVE: 223. applyHeaderPadding(event); 224. break; 225. } 226. return super.onTouchEvent(event); 227. } 228. 229. private void applyHeaderPadding(MotionEvent ev) { 230. final int historySize = ev.getHistorySize(); 231. 232. // Workaround for getPointerCount() which is unavailable in 1.5 233. // (it's always 1 in 1.5) 234. int pointerCount = 1; 235. try { 236. class.getMethod("getPointerCount"); 237. pointerCount = (Integer)method.invoke(ev); 238. catch (NoSuchMethodException e) { 239. 1; 240. catch (IllegalArgumentException e) { 241. throw e; 242. catch (IllegalAccessException e) { 243. "unexpected " + e); 244. catch (InvocationTargetException e) { 245. "unexpected " + e); 246. } 247. 248. for (int h = 0; h < historySize; h++) { 249. for (int p = 0; p < pointerCount; p++) { 250. if (mRefreshState == RELEASE_TO_REFRESH) { 251. if (isVerticalFadingEdgeEnabled()) { 252. false); 253. } 254. 255. int historicalY = 0; 256. try { 257. // For Android > 2.0 258. class.getMethod( 259. "getHistoricalY", Integer.TYPE, Integer.TYPE); 260. historicalY = ((Float) method.invoke(ev, p, h)).intValue(); 261. catch (NoSuchMethodException e) { 262. // For Android < 2.0 263. int) (ev.getHistoricalY(h)); 264. catch (IllegalArgumentException e) { 265. throw e; 266. catch (IllegalAccessException e) { 267. "unexpected " + e); 268. catch (InvocationTargetException e) { 269. "unexpected " + e); 270. } 271. 272. // Calculate the padding to apply, we divide by 1.7 to 273. // simulate a more resistant effect during pull. 274. int topPadding = (int) (((historicalY - mLastMotionY) 275. 1.7); 276. 277. // 设置上、下、左、右四个位置的间隙间隙 278. mRefreshHeaderView.setPadding( 279. mRefreshHeaderView.getPaddingLeft(), 280. topPadding, 281. mRefreshHeaderView.getPaddingRight(), 282. mRefreshHeaderView.getPaddingBottom()); 283. } 284. } 285. } 286. } 287. 288. /** 289. * Sets the header padding back to original size. 290. * 设置头部填充会原始大小 291. */ 292. private void resetHeaderPadding() { 293. mRefreshHeaderView.setPadding( 294. mRefreshHeaderView.getPaddingLeft(), 295. mRefreshOriginalTopPadding, 296. mRefreshHeaderView.getPaddingRight(), 297. mRefreshHeaderView.getPaddingBottom()); 298. } 299. 300. /** 301. * Resets the header to the original state. 302. * 重新设置头部为原始状态 303. */ 304. private void resetHeader() { 305. if (mRefreshState != TAP_TO_REFRESH) { 306. mRefreshState = TAP_TO_REFRESH; 307. 308. resetHeaderPadding(); 309. 310. // Set refresh view text to the pull label 311. mRefreshViewText.setText(R.string.pull_to_refresh_tap_label); 312. // Replace refresh drawable with arrow drawable 313. mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow); 314. // Clear the full rotation animation 315. mRefreshViewImage.clearAnimation(); 316. // Hide progress bar and arrow. 317. mRefreshViewImage.setVisibility(View.GONE); 318. mRefreshViewProgress.setVisibility(View.GONE); 319. } 320. } 321. 322. /** 323. * 重设ListView尾部视图为初始状态 324. */ 325. private void resetFooter() { 326. if(mLoadState != TAP_TO_LOADMORE) { 327. mLoadState = TAP_TO_LOADMORE; 328. 329. // 进度条设置为不可见 330. mLoadMoreProgress.setVisibility(View.GONE); 331. // 按钮的文本替换为“加载更多” 332. mLoadMoreText.setText(R.string.loadmore_label); 333. } 334. 335. } 336. 337. 338. /** 339. * 测量视图的大小 340. * @param child 341. */ 342. private void measureView(View child) { 343. ViewGroup.LayoutParams p = child.getLayoutParams(); 344. if (p == null) { 345. new ViewGroup.LayoutParams( 346. ViewGroup.LayoutParams.MATCH_PARENT, 347. ViewGroup.LayoutParams.WRAP_CONTENT); 348. } 349. 350. int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 351. 0 + 0, p.width); 352. int lpHeight = p.height; 353. int childHeightSpec; 354. if (lpHeight > 0) { 355. childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); 356. else { 357. 0, MeasureSpec.UNSPECIFIED); 358. } 359. child.measure(childWidthSpec, childHeightSpec); 360. } 361. 362. @Override 363. public void onScroll(AbsListView view, int firstVisibleItem, 364. int visibleItemCount, int totalItemCount) { 365. // When the refresh view is completely visible, change the text to say 366. // "Release to refresh..." and flip the arrow drawable. 367. if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL 368. && mRefreshState != REFRESHING) { 369. if (firstVisibleItem == 0) { // 如果第一个可见条目为0 370. // 让指示箭头变得可见 371. /**如果头部视图相对与父容器的位置大于其自身高度+20或者头部视图的顶部位置>0,并且要在刷新状态不等于"释放以刷新"**/ 372. if ((mRefreshHeaderView.getBottom() > mRefreshViewHeight + 20 373. 0) 374. && mRefreshState != RELEASE_TO_REFRESH) { 375. // 设置刷新文本为"Release to refresh..." 376. // 清除动画 377. // 启动动画 378. // 更改刷新状态为“释放以刷新" 379. else if (mRefreshHeaderView.getBottom() < mRefreshViewHeight + 20 380. && mRefreshState != PULL_TO_REFRESH) { 381. // 设置刷新文本为"Pull to refresh..." 382. if (mRefreshState != TAP_TO_REFRESH) { 383. mRefreshViewImage.clearAnimation(); 384. mRefreshViewImage.startAnimation(mReverseFlipAnimation); 385. } 386. mRefreshState = PULL_TO_REFRESH; 387. } 388. else { 389. // 让刷新箭头不可见 390. // 重新设置头部为原始状态 391. } 392. else if (mCurrentScrollState == SCROLL_STATE_FLING 393. 0 394. && mRefreshState != REFRESHING) { 395. 1); 396. } 397. 398. if (mOnScrollListener != null) { 399. mOnScrollListener.onScroll(view, firstVisibleItem, 400. visibleItemCount, totalItemCount); 401. } 402. } 403. 404. @Override 405. public void onScrollStateChanged(AbsListView view, int scrollState) { 406. mCurrentScrollState = scrollState; 407. 408. if (mOnScrollListener != null) { 409. mOnScrollListener.onScrollStateChanged(view, scrollState); 410. } 411. } 412. 413. 414. /**为刷新做准备**/ 415. public void prepareForRefresh() { 416. resetHeaderPadding(); 417. 418. // 去掉刷新的箭头 419. // We need this hack, otherwise it will keep the previous drawable. 420. null); 421. // 圆形进度条变为可见 422. 423. // Set refresh view text to the refreshing label 424. mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label); 425. 426. mRefreshState = REFRESHING; 427. } 428. 429. /**为加载更多做准备**/ 430. public void prepareForLoadMore() { 431. mLoadMoreProgress.setVisibility(View.VISIBLE); 432. mLoadMoreText.setText(R.string.loading_label); 433. mLoadState = LOADING; 434. } 435. 436. public void onRefresh() { 437. "onRefresh"); 438. 439. if (mOnRefreshListener != null) { 440. mOnRefreshListener.onRefresh(); 441. } 442. } 443. 444. public void OnLoadMore() { 445. "onLoadMore"); 446. if(mOnRefreshListener != null) { 447. mOnRefreshListener.onLoadMore(); 448. } 449. } 450. 451. /** 452. * Resets the list to a normal state after a refresh. 453. * @param lastUpdated Last updated at. 454. */ 455. public void onRefreshComplete(CharSequence lastUpdated) { 456. // 显示更新时间 457. onRefreshComplete(); 458. } 459. 460. /** 461. * Resets the list to a normal state after a refresh. 462. */ 463. public void onRefreshComplete() { 464. "onRefreshComplete"); 465. 466. resetHeader(); 467. 468. // If refresh view is visible when loading completes, scroll down to 469. // the next item. 470. if (mRefreshHeaderView.getBottom() > 0) { 471. invalidateViews(); 472. 1); 473. } 474. } 475. 476. public void onLoadMoreComplete() { 477. "onLoadMoreComplete"); 478. resetFooter(); 479. } 480. 481. /** 482. * Invoked when the refresh view is clicked on. This is mainly used when 483. * there's only a few items in the list and it's not possible to drag the 484. * list. 485. * 点击刷新 486. */ 487. private class OnClickRefreshListener implements OnClickListener { 488. 489. @Override 490. public void onClick(View v) { 491. if (mRefreshState != REFRESHING) { 492. prepareForRefresh(); 493. onRefresh(); 494. } 495. } 496. 497. } 498. 499. /** 500. * 501. * @author wwj 502. * 加载更多 503. */ 504. private class OnClickLoadMoreListener implements OnClickListener { 505. 506. @Override 507. public void onClick(View v) { 508. if(mLoadState != LOADING) { 509. prepareForLoadMore(); 510. OnLoadMore(); 511. } 512. } 513. } 514. 515. /** 516. * Interface definition for a callback to be invoked when list should be 517. * refreshed. 518. * 接口定义一个回调方法当列表应当被刷新 519. */ 520. public interface OnRefreshListener { 521. /** 522. * Called when the list should be refreshed. 523. * 当列表应当被刷新是调用这个方法 524. *

525. * A call to {@link PullToRefreshListView #onRefreshComplete()} is 526. * expected to indicate that the refresh has completed. 527. */ 528. public void onRefresh(); 529. 530. public void onLoadMore(); 531. } 532. }

使用方法:

[java] 

1. package com.markupartist.android.example.pulltorefresh; 2. 3. import java.text.SimpleDateFormat; 4. import java.util.Arrays; 5. import java.util.Date; 6. import java.util.LinkedList; 7. 8. import android.app.Activity; 9. import android.content.Context; 10. import android.os.AsyncTask; 11. import android.os.Bundle; 12. import android.widget.ArrayAdapter; 13. 14. import com.markupartist.android.widget.PullToRefreshListView; 15. import com.markupartist.android.widget.PullToRefreshListView.OnRefreshListener; 16. 17. public class PullToRefreshActivity extends Activity { 18. private LinkedList mListItems; 19. public static PullToRefreshListView weiboListView; 20. 21. /** Called when the activity is first created. */ 22. @Override 23. public void onCreate(Bundle savedInstanceState) { 24. super.onCreate(savedInstanceState); 25. setContentView(R.layout.pull_to_refresh); 26. weiboListView = (PullToRefreshListView) findViewById(R.id.weibolist); 27. 28. // Set a listener to be invoked when the list should be refreshed. 29. new OnRefreshListener() { 30. @Override 31. public void onRefresh() { 32. // Do work to refresh the list here. 33. new GetDataTask(PullToRefreshActivity.this, 0).execute(); 34. } 35. 36. @Override 37. public void onLoadMore() { 38. new GetDataTask(PullToRefreshActivity.this, 1).execute(); 39. } 40. }); 41. 42. new LinkedList(); 43. mListItems.addAll(Arrays.asList(mStrings)); 44. 45. new ArrayAdapter(this, 46. android.R.layout.simple_list_item_1, mListItems); 47. 48. weiboListView.setAdapter(adapter); 49. } 50. 51. private class GetDataTask extends AsyncTask { 52. private Context context; 53. private int index; 54. 55. public GetDataTask(Context context, int index) { 56. this.context = context; 57. this.index = index; 58. } 59. 60. @Override 61. protected String[] doInBackground(Void... params) { 62. // Simulates a background job. 63. try { 64. 2000); 65. catch (InterruptedException e) { 66. ; 67. } 68. return mStrings; 69. } 70. 71. @Override 72. protected void onPostExecute(String[] result) { 73. if (index == 0) { 74. // 将字符串“Added after refresh”添加到顶部 75. "Added after refresh..."); 76. 77. new SimpleDateFormat( 78. "yyyy年MM月dd日 HH:mm"); 79. new Date()); 80. // Call onRefreshComplete when the list has been refreshed. 81. weiboListView.onRefreshComplete(date); 82. else if (index == 1) { 83. "Added after loadmore..."); 84. weiboListView.onLoadMoreComplete(); 85. } 86. 87. super.onPostExecute(result); 88. } 89. } 90. 91. public static String[] mStrings = { "一条微博", "两条微博", "三条微博", "四条微博", "五条微博", 92. "六条微博", "七条微博", "八条微博", "九条微博", "十条微博", "十一条微博", "十二条微博" }; 93. 94. }

下拉刷新的那个头部布局

/2013.08.22_PullToRefresh_ListView_Demo/res/layout/pull_to_refresh_header.xml

[html] 

1. 2. 17. 18. 24. 25. 26. 27. 38. 39. 40. 50. 51. 52. 62. 63. 72. 73.

加载更多的底部布局

/2013.08.22_PullToRefresh_ListView_Demo/res/layout/loadmore_footer.xml

[html] 

1. 2. 9. 10.


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3