由于公司的需要,做了一个小组件。

先阶段只完成了2个功能:

 

  1. 前端分页功能。
  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 {

		@Override
		public void onClick(View arg0) {
			doLoading();
		}
	}

	private class OnScroll implements OnScrollListener {

		@Override
		public void onScroll(AbsListView view, int firstVisibleItem,
				int visibleItemCount, int totalItemCount) {
			if (isOver)
				return;
			lastItem = firstVisibleItem + visibleItemCount - 1;
		}

		@Override
		public 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;
		else
			curtCount = dataList.size();
	}

	@Override
	public final int getCount() {
		return curtCount;
	}

	@Override
	public 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());
		else
			toCount = 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);

 

 后台分页:

 

	// 后台分页示例2
		lv2 = (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() {

			@Override
			public void load() {
				testRequest();
			}
		});

// 此处模拟向服务器发送异步请求
	private void testRequest() {
		Thread mThread = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					Thread.sleep(2000);
					mHandler.sendEmptyMessage(TOAST_MSG_SEND);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		mThread.start();
	}

	// 模拟请求成功。
	private Handler mHandler = new Handler() {

		@Override
		public 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即可
			}
		}
	};

  

 

版权声明:本文为匿名原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: