PullToRefreshListView是PullToRefreshBase的子类,而PullToRefreshBase继承LinearLayout。先分析父类PullToRefreshBase。在PullToRefreshBase的init()方法中
private void init(Context context, AttributeSet attrs) {
switch (getPullToRefreshScrollDirection()) {
case HORIZONTAL:
setOrientation(LinearLayout.HORIZONTAL);
break;
case VERTICAL:
default:
setOrientation(LinearLayout.VERTICAL);
break;
}
setGravity(Gravity.CENTER);
ViewConfiguration config = ViewConfiguration.get(context);
mTouchSlop = config.getScaledTouchSlop();
// Styleables from XML
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.PullToRefresh);
if (a.hasValue(R.styleable.PullToRefresh_ptrMode)) {
mMode = Mode.mapIntToValue(a.getInteger(
R.styleable.PullToRefresh_ptrMode, 0));
}
if (a.hasValue(R.styleable.PullToRefresh_ptrAnimationStyle)) {
mLoadingAnimationStyle = AnimationStyle.mapIntToValue(a.getInteger(
R.styleable.PullToRefresh_ptrAnimationStyle, 0));
}
// Refreshable View
// By passing the attrs, we can add ListView/GridView params via XML
mRefreshableView = createRefreshableView(context, attrs);
addRefreshableView(context, mRefreshableView);
// We need to create now layouts now
createDefaultLoadingLayout(context, mMode, a);
/**
* Styleables from XML
*/
if (a.hasValue(R.styleable.PullToRefresh_ptrRefreshableViewBackground)) {
Drawable background = a
.getDrawable(R.styleable.PullToRefresh_ptrRefreshableViewBackground);
if (null != background) {
mRefreshableView.setBackgroundDrawable(background);
}
} else if (a
.hasValue(R.styleable.PullToRefresh_ptrAdapterViewBackground)) {
Utils.warnDeprecation("ptrAdapterViewBackground",
"ptrRefreshableViewBackground");
Drawable background = a
.getDrawable(R.styleable.PullToRefresh_ptrAdapterViewBackground);
if (null != background) {
mRefreshableView.setBackgroundDrawable(background);
}
}
if (a.hasValue(R.styleable.PullToRefresh_ptrOverScroll)) {
mOverScrollEnabled = a.getBoolean(
R.styleable.PullToRefresh_ptrOverScroll, true);
}
if (a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) {
mScrollingWhileRefreshingEnabled = a
.getBoolean(
R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled,
false);
}
// Let the derivative classes have a go at handling attributes, then
// recycle them...
handleStyledAttributes(a);
a.recycle();
// Finally update the UI for the modes
updateUIForMode();
}
(1)
getPullToRefreshScrollDirection在子类
PullToRefreshListView被重写
public final Orientation getPullToRefreshScrollDirection() {
return Orientation.VERTICAL;
}
所以
PullToRefreshListView就是一个
Orientation为
VERTICAL的
LinearLayout
(2) mRefreshableView = createRefreshableView(context, attrs); mRefreshableView是泛型T,在子类 PullToRefreshListView 中
public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView> {
......
@Override
protected ListView createRefreshableView(Context context, AttributeSet attrs) {
ListView lv = createListView(context, attrs);
// Set it to this so it can be used in ListActivity/ListFragment
lv.setId(android.R.id.list);
return lv;
}
......
}
所以使用
PullToRefreshListView 时
mRefreshableView
实际上就是
ListView。当然,我们也可以改写此泛型,替换成我们自定义的ListView。比如
其中
SwipeMenuListView是可以实现侧拉删除的ListView,改写后的
PullToRefreshSwipeListView就能实现
侧拉删除功能同时,拥有
PullToRefreshListView的上拉加载下拉刷新功能。
(3)addRefreshableView(context, mRefreshableView)方法
private void addRefreshableView(Context context, T refreshableView) {
mRefreshableViewWrapper = new FrameLayout(context);
mRefreshableViewWrapper.addView(refreshableView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
addViewInternal(mRefreshableViewWrapper, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
PullToRefreshListView添加了一个FrameLayout,FrameLayout里面又添加了mRefreshableView,即添加了ListView。addViewInternal()方法作用和addView ()方法类似
(4)createDefaultLoadingLayout(context, mMode, a)方法最后会通过
LoadingLayout createTopLoadingLayout(Context context, Mode mode,
Orientation scrollDirection, TypedArray attrs) {
if (this == FLIP_NOROTATE) {
return new FlipLoadingLayout(context, mode, scrollDirection,
attrs);
}
return createLoadingLayout(context, mode, scrollDirection, attrs);
}
生成mHeaderLayout
LoadingLayout createBootomLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) { if (this == NOROTATE || this == FLIP_NOROTATE) { return new RefRotateLoadingLayout(context, mode, scrollDirection, attrs); } return createLoadingLayout(context, mode, scrollDirection, attrs); }
生成mFooterLayout。
由private AnimationStyle mLoadingAnimationStyle = AnimationStyle.getDefault();知默认this是FLIP_NOROTATE。FlipLoadingLayout 和RefRotateLoadingLayout都是FrameLayout的子类,用于实现头布局和尾布局
(5)handleStyledAttributes(a);PullToRefreshListView会对这个方法进行重写
@Override protected void handleStyledAttributes(TypedArray a) { super.handleStyledAttributes(a); mListViewExtrasEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true); if (mListViewExtrasEnabled) { final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL); // Create Loading Views ready for use later FrameLayout frame = new FrameLayout(getContext()); mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a); mHeaderLoadingView.setVisibility(View.GONE); frame.addView(mHeaderLoadingView, lp); mRefreshableView.addHeaderView(frame, null, false); mLvFooterLoadingFrame = new FrameLayout(getContext()); mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a); mFooterLoadingView.setVisibility(View.GONE); mLvFooterLoadingFrame.addView(mFooterLoadingView, lp); /** * If the value for Scrolling While Refreshing hasn't been * explicitly set via XML, enable Scrolling While Refreshing. */ if (!a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) { setScrollingWhileRefreshingEnabled(true); } } }
此方法主要是给PullToRefreshListView中ListView增加HeaderView和FooterLoadingView。此时可以得出PullToRefreshListView的嵌套关系
(6)updateUIForMode()方法,此方法是通过我们设置的Mode来确定是否显示headView和foodView
protected void updateUIForMode() {
// We need to use the correct LayoutParam values, based on scroll
// direction
final LayoutParams lp = getLoadingLayoutLayoutParams();
// 移除headView,防止重复addViewInternal(mHeaderLayout, 0, lp);
if (this == mHeaderLayout.getParent()) {
removeView(mHeaderLayout);
}
//当我们设置Mode为PULL_FROM_START或BOTH时showHeaderLoadingLayout()///方法返回为true
if (mMode.showHeaderLoadingLayout()) {
addViewInternal(mHeaderLayout, 0, lp);
}
// Remove Footer, and then add Footer Loading View again if needed
if (this == mFooterLayout.getParent()) {
removeView(mFooterLayout);
}
if (mMode.showFooterLoadingLayout()) {
addViewInternal(mFooterLayout, lp);
}
// Hide Loading Views
refreshLoadingViewsSize();
// If we're not using Mode.BOTH, set mCurrentMode to mMode, otherwise
// set it to pull down
mCurrentMode = (mMode != Mode.BOTH && mMode != Mode.REFROTATE) ? mMode
: Mode.PULL_FROM_START;
}
至此,PullToRefreshListView的基本结构应该有个大体了解了.个人认为PullToRefreshListView嵌套的有点多了,我在项目中就有因为这个出现过问题:点击打开链接