接着上一篇,进行代码分析,先贴上简化后的几段关键代码:
一、自定义组合控件初始化
简单点说就是在组合控件初始化的时候就在初始位置添加头部视图。
public PullToRefreshView(Context context) { super(context); init(); } private void init() { // Load all of the animations we need in code rather than through XML // 简化头部和脚部箭头转向动画 mInflater = LayoutInflater.from(getContext()); // header view 在此添加,保证是第一个添加到linearlayout的最上端 addHeaderView(); } private void addHeaderView() { // header view mHeaderView = mInflater.inflate(R.layout.refresh_header, this, false); // 简化头部视图内对象的创建过程 // header layout measureView(mHeaderView); //自定义的子控件尺寸测量方法 mHeaderViewHeight = mHeaderView.getMeasuredHeight(); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeaderViewHeight); // 设置topMargin的值为负的header View高度,即将其隐藏在最上方 params.topMargin = -(mHeaderViewHeight); // mHeaderView.setLayoutParams(params1); addView(mHeaderView, params); }二、子视图的尺寸测量
就是通过给子视图制定一些规则,让其宽度填充父视图,高度自适应,因为这里继承LinearLayout,但是没有指定Orientation,同时也可以强制头部宽度填充。
private void measureView(View child) { ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); }三、添加下拉尾部
尾部视图的获取和头部相似,只不过这里重写了onFinishInflate()方法,确保将其天际到Linearlayout的最后。这里内容视图的方式和android官方的下拉刷新SwapRefreshView类似,都是硬编码获取指定位置的视图。官方的下拉刷新好像只允许包含一个子视图。
@Override protected void onFinishInflate() { super.onFinishInflate(); // footer view 在此添加保证添加到linearlayout中的最后 addFooterView(); initContentAdapterView(); }
private void initContentAdapterView() { int count = getChildCount(); if (count < 3) { throw new IllegalArgumentException( "this layout must contain 3 child views,and AdapterView or ScrollView must in the second position!"); } View view = null; for (int i = 0; i < count - 1; ++i) { view = getChildAt(i); if (view instanceof AdapterView<?>) { mAdapterView = (AdapterView<?>) view; } if (view instanceof ScrollView) { // finish later mScrollView = (ScrollView) view; } } if (mAdapterView == null && mScrollView == null) { throw new IllegalArgumentException( "must contain a AdapterView or ScrollView in this layout!"); } }
四、头部下拉刷新和尾部上拉加载的时间监听器接口
这里用到的就是接口回调方式实现的刷新事件监听,在外层实现这些接口,可以执行刷新事件的流程。以及是否允许上拉和下拉的限制。
/** * set headerRefreshListener * * @description * @param headerRefreshListener * hylin 2012-7-31上午11:43:58 */ public void setOnHeaderRefreshListener( OnHeaderRefreshListener headerRefreshListener) { mOnHeaderRefreshListener = headerRefreshListener; } public void setOnFooterRefreshListener( OnFooterRefreshListener footerRefreshListener) { mOnFooterRefreshListener = footerRefreshListener; } /** * Interface definition for a callback to be invoked when list/grid footer * view should be refreshed. */ public interface OnFooterRefreshListener { public void onFooterRefresh(PullToRefreshView view); } /** * Interface definition for a callback to be invoked when list/grid header * view should be refreshed. */ public interface OnHeaderRefreshListener { public void onHeaderRefresh(PullToRefreshView view); } public boolean isEnablePullTorefresh() { return enablePullTorefresh; } public void setEnablePullTorefresh(boolean enablePullTorefresh) { this.enablePullTorefresh = enablePullTorefresh; } public boolean isEnablePullLoadMoreDataStatus() { return enablePullLoadMoreDataStatus; } public void setEnablePullLoadMoreDataStatus(boolean enablePullLoadMoreDataStatus) { this.enablePullLoadMoreDataStatus = enablePullLoadMoreDataStatus; }