Android ListView 分页功能,包含前端分页,服务器分页
由于公司的需要,做了一个小组件。
先阶段只完成了2个功能:
[*]前端分页功能。
[*]服务器分页。
public class PaginationListview extends ListView {public PaginationListview(Context context) {super(context);this.context = context;init();}/** * 初始化工作 */private void init() {footView = createFootView();addFooterView(footView);initListener();}/** * 创建listview的footview ** @return footView */private View createFootView() {LinearLayout ll = new LinearLayout(context);AbsListView.LayoutParams params = new AbsListView.LayoutParams(MATCH_PARENT, 50);ll.setLayoutParams(params);LinearLayout.LayoutParams params_m = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);ll_loadingmore = new LinearLayout(context);ll_loadingmore.setLayoutParams(params_m);ll_loadingmore.setGravity(Gravity.CENTER);ll_loadingmore.setOrientation(LinearLayout.HORIZONTAL);addLoadView(ll);addProgress();addLoadMoreText();ll.addView(ll_loadingmore);return ll;}/** * 加载更多的按钮 * @param parentViewGroup */private void addLoadView(ViewGroup parentViewGroup) {tv_more = new TextView(context);LinearLayout.LayoutParams params_m = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);tv_more.setLayoutParams(params_m);tv_more.setGravity(Gravity.CENTER);tv_more.setText(TEXT_LOADING);tv_more.setTextColor(TEXT_COLOR_BLACK);tv_more.setTextSize(TEXT_SIZE);parentViewGroup.addView(tv_more);}/** * 正在加载时的显示出来组件,添加一个进度圈 */private void addProgress() {ProgressBar progressBar = new ProgressBar(context, null,android.R.attr.progressBarStyleSmallInverse);progressBar.setIndeterminate(true);LinearLayout.LayoutParams params_w = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);progressBar.setLayoutParams(params_w);ll_loadingmore.addView(progressBar);}/** * 正在加载时的显示出来组件,添加一个提示文字 */private void addLoadMoreText() {TextView tv = new TextView(context);LinearLayout.LayoutParams params_w = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);tv.setLayoutParams(params_w);tv.setText(TEXT_ON_LOADING);tv.setTextColor(TEXT_COLOR_BLACK);tv.setTextSize(TEXT_SIZE);ll_loadingmore.addView(tv);}/** ** @param is * 是否打开前台分页功能 */void setIsPageOpen(boolean is) {this.isUIPage = is;}private class FootViewClick implements View.OnClickListener {@Overridepublic void onClick(View arg0) {doLoading();}}private class OnScroll implements OnScrollListener {@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {if (isOver)return;lastItem = firstVisibleItem + visibleItemCount - 1;}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if (isOver)return;if (lastItem == getAdapter().getCount() - 1&& scrollState == OnScrollListener.SCROLL_STATE_IDLE) {doLoading();}}}private void initListener() {if (loadWay == CLICK_TO_LOAD) {footView.setOnClickListener(new FootViewClick());} else if (loadWay == SCROLL_BOTTOM_LOAD) {footView.setOnClickListener(null);setOnScrollListener(new OnScroll());tv_more.setText(TEXT_LOADING_SCROLL);}}private void doLoading() {tv_more.setVisibility(View.GONE);ll_loadingmore.setVisibility(View.VISIBLE);if (isUIPage) {paginationAdapter.refreshCurtCount();} else {if (mLoadMore != null) {mLoadMore.load();}}}/** * 重写此方法,获取相关对象 ** @param adapter * 必须是PaginationAdapter类 */public void setAdapter(PaginationAdapter<?> adapter) {setAdapter((ListAdapter) adapter);this.paginationAdapter = adapter;paginationAdapter.setListView(this);}/** ** @param loadMore * 必须实现此接口中的load方法 */public void setLoadMore(LoadMore loadMore) {this.mLoadMore = loadMore;doLoading();}/** * 异步获取数据的方法必须放在此处。典型的情况下:在这里发送一个request,在该请求的onSuccess中调用finishLoading。 */public interface LoadMore {void load();}/** * 当在某种情况下,例如在刷新页面,清空数据源后,调用此方法让listview的圈圈转起来。 */public void startLoading() {doLoading();}/** ** 当加载完后,数据源增加完毕后必须调用此方法,典型的情况下,在请求成功或失败时调用此方法。 ** @param isOver * 如果确认已经加载完所有数据,传入true,此后将不再显示加载更多。若还有数据,参数为false */public void finishLoading(boolean isOver) {paginationAdapter.notifyDataSetChanged();tv_more.setVisibility(View.VISIBLE);ll_loadingmore.setVisibility(View.GONE);this.isOver = isOver;if (isOver) {tv_more.setText(TEXT_FINISH_LOADING);footView.setOnClickListener(null);}}/** * 设置加载的方式。 ** @param way * CLICK_TO_LOAD:用户点击"加载更多",才会加载。默认采用此种方式。 * SCROLL_BOTTOM_LOAD:当用户滑到底部的时候自动加载 **/public void setLoadMoreWay(int way) {loadWay = way;initListener();}}
如果要实现比较简便的前端分页功能。比如我们公司就要控制一次显示出来的Item项数,以控制每项加载图片的线程,这时要继承一个Adapter:
public abstract class PaginationAdapter<T> extends BaseAdapter {/** * 更改无参构造方法,强制后代必须调用super(List); */private PaginationAdapter() {super();Log.d(TAG, "private PaginationAdapter()");}/** * 子类创建时必须调用此方法,以让本类获得数据源对象。 ** @param list * 数据源list集合。 */protected PaginationAdapter(List<T> list) {super();Log.d(TAG, "public PaginationAdapter(List<T> list)");this.dataList = list;if (dataList == null)curtCount = 0;elsecurtCount = dataList.size();}@Overridepublic final int getCount() {return curtCount;}@Overridepublic void notifyDataSetChanged() {if (pageSize == 0) {curtCount = dataList.size();}super.notifyDataSetChanged();}void refreshCurtCount() {int toCount;if (curtCount == 0 && firstPageSize != 0)toCount = Math.min(curtCount + firstPageSize, dataList.size());elsetoCount = Math.min(curtCount + pageSize, dataList.size());curtCount = toCount;notifyDataSetChanged();paginationListview.finishLoading(curtCount == dataList.size() ? true: false);}void setListView(PaginationListview pListview) {this.paginationListview = pListview;if (pageSize > 0) {paginationListview.setIsPageOpen(true);refreshCurtCount();}}/** * 设置第一页的大小。若没有使用此方法,则默认使用setPageSize中的每页大小 ** @param firstPageSize */public void setFirsetPageSize(int firstPageSize) {this.firstPageSize = firstPageSize;}/** * 如果使用前端分页(Adapter在构建时,数据源就已经是完整的,只需要在此处设置每页/每次显示的大小即可)。如果后台分页,则不需要调用此方法 ** @param pageSize * 页面大小(每次点击加载更多时,增加显示的条目数量) */public void setPageSize(int pageSize) {this.curtCount = 0;this.pageSize = pageSize;}/** * 使用后台分页模式时,在服务器请求成功后,传入新增的list集合即可。 ** @param list * 新增加的list集合。注意此list必须和adapter构建时的list为同一类型。 * @param isOver * 是否还有更多的数据,false表示不再继续显示加载更多 */public void addPageList(List<T> list, boolean isOver) {for (T t : list)dataList.add(t);notifyDataSetChanged();paginationListview.finishLoading(isOver);}}
使用方法非常简单。
前端分页方法:
// 使用前台分页方式。List<String> strList = new ArrayList<String>();for (int i = 0; i < 45; i++)strList.add(String.valueOf(strList.size()) + " ~~");lv3 = (PaginationListview) findViewById(R.id.paginationListview3);adapter3 = new TestAdapter(this, strList);// 设置首页大小和之后的每页大小adapter3.setFirsetPageSize(20);adapter3.setPageSize(10);lv3.setAdapter(adapter3);
后台分页:
// 后台分页示例2lv2 = (PaginationListview) findViewById(R.id.paginationListview2);list = new ArrayList<String>();adapter2 = new TestAdapter(this, list);lv2.setAdapter(adapter2);// 设置加载更多的方式lv2.setLoadMoreWay(PaginationListview.SCROLL_BOTTOM_LOAD);lv2.setLoadMore(new LoadMore() {@Overridepublic void load() {testRequest();}});// 此处模拟向服务器发送异步请求private void testRequest() {Thread mThread = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(2000);mHandler.sendEmptyMessage(TOAST_MSG_SEND);} catch (InterruptedException e) {e.printStackTrace();}}});mThread.start();}// 模拟请求成功。private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case TOAST_MSG_SEND:// 修改数据源for (int i = 0; i < 10; i++)tempList.add("ListB" + tempList.size() + i);adapter2.addPageList(tempList, false);//当数据加载完,传入true即可}}}; http://dl.iteye.com/upload/attachment/0075/7934/f041984f-e59c-3d88-9831-3a7a691a1da8.png
页:
[1]