Android PullToRefresh 分析之二、UI结构
2015-12-18 15:34
561 查看
转载请标明出处:
/article/7691964.html
本文出自:【Kevin.zhou的博客】
前言:接着上一篇《Android PullToRefresh 分析之一、初识PullToRefresh》,这一篇主要分析UI结构,尽可能每一篇只说一点,然后将该点讲解清楚。
![](http://img.blog.csdn.net/20151218152120805?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
刷新加载的方向是怎样的,通常的是竖向,万一奇葩的需求提出横向呢?
"内容区域"应该显示什么?怎么设置才好扩展?
怎么判断到顶部了,要触发刷新动作?
怎么判断到底部了,要触发加载操作?
OK,来分析下这四个问题:
对于问题一,非常简单,我们可以提供设置方向的配置;
对于问题二,似乎比较棘手,其实也比较好扩展,我们提供一个容器,想放什么布局都可以;
对于问题三、四不同的控件都有判断到顶部和尾部的方法。
这样,只有在基类中将配置的方法抽象出来让不同的实现去处理就好了。
来看下PullToRefreshScrollView都有哪些方法:
![](http://img.blog.csdn.net/20151218152419528?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
比较简单,只是覆盖了父类的四个方法,通过名称可以看出。
getPullToRefreshScrollDirection() 为获取刷新加载的方向,是横向还是竖向;
createRefreshableView() 为生成刷新加载View,这里生成的是ScrollView;
isReadyForPullStart() 为判断是否促发了刷新操作;
isReadyForPullEnd() 为判断是否触发了加载操作;
是不是很眼熟,不错这就是我们提出的四个问题,也就是扩展一个控件只需要实现这四个方法就可以了。但是这几个方法是如何被调用的呢?我们来到它爸爸的类PullToRefreshBase瞅瞅。
![](http://img.blog.csdn.net/20151218152526010?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
通过类的继承关系就可以看到继承自LinearLayout,再来看下构造函数:
省略掉我们暂时不关心的代码,接下来主要分析标注的五段:
①、首先就是抽象的getPullToRefreshScrollDirection()来获取刷新加载的方向,该方法在子类中去实现,也是对应我们在思考中提出的问题一;
②、获取配置的刷新加载模式,有其中Mode为一个内部的枚举,有DISABLED、PULL_FROM_START、PULL_FROM_END、BOTH、MANUAL_REFRESH_ONLY即不允许刷新加载、从头部刷新、从尾部加载、刷新加载都支持、只允许手动刷新加载,对应的在布局中的配置为
③、createRefreshableView()生成刷新加载View,该方法也是抽象的由子类去实现;
④、在生成刷新加载View后调用了addRefreshableView(),通过名称为加载到View结构上,
把刷新加载View添加到FrameLayout上,然后将该FrameLayout 加载到自身LinearLayout上,可见这个名叫mRefreshableViewWrapper 的FrameLayout就是刷新加载View的父View。前面已经提到过,就是对应的我们在思考中提出的问题二;
⑤、初始"刷新头部"和"加载外部"布局,在初始化头部和尾部的时候都是调用的createLoadingLayout()方法,只是传入的参数不同;
![](http://img.blog.csdn.net/20151218153125504?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
,另一个是这样的
![](http://img.blog.csdn.net/20151218153146645?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
。
⑥、最后调用了updateUIForMode(),即根据刷新加载的模式来更新UI:
在这里把头部和尾部 加载到自身LinearLayout上,并隐藏头部和尾部。
至此,怎么生成"刷新头部"、"加载尾部"及"内容区域"并将它们都加载到自身的LinearLayout上就清楚了。
PullToRefresh 分析之三、手势响应》中将主要分析是如何响应手指滑动事件的。
/article/7691964.html
本文出自:【Kevin.zhou的博客】
前言:接着上一篇《Android PullToRefresh 分析之一、初识PullToRefresh》,这一篇主要分析UI结构,尽可能每一篇只说一点,然后将该点讲解清楚。
一、 问题思考
我们首先把上一篇的一个图拿过来,来分析这三段,如果让我们封装一个刷新加载框架应该怎样写,首先提出几个问题:刷新加载的方向是怎样的,通常的是竖向,万一奇葩的需求提出横向呢?
"内容区域"应该显示什么?怎么设置才好扩展?
怎么判断到顶部了,要触发刷新动作?
怎么判断到底部了,要触发加载操作?
OK,来分析下这四个问题:
对于问题一,非常简单,我们可以提供设置方向的配置;
对于问题二,似乎比较棘手,其实也比较好扩展,我们提供一个容器,想放什么布局都可以;
对于问题三、四不同的控件都有判断到顶部和尾部的方法。
这样,只有在基类中将配置的方法抽象出来让不同的实现去处理就好了。
二、UI源码分析
通过上面问题的思考,就给下面的源码分析做好了铺垫,不要骂我唐僧(太啰嗦了),大牛请无视,只是为了让刚入门的朋友也能理清思路。还是以简单的PullToRefreshScrollView来分析。来看下PullToRefreshScrollView都有哪些方法:
比较简单,只是覆盖了父类的四个方法,通过名称可以看出。
getPullToRefreshScrollDirection() 为获取刷新加载的方向,是横向还是竖向;
createRefreshableView() 为生成刷新加载View,这里生成的是ScrollView;
isReadyForPullStart() 为判断是否促发了刷新操作;
isReadyForPullEnd() 为判断是否触发了加载操作;
是不是很眼熟,不错这就是我们提出的四个问题,也就是扩展一个控件只需要实现这四个方法就可以了。但是这几个方法是如何被调用的呢?我们来到它爸爸的类PullToRefreshBase瞅瞅。
通过类的继承关系就可以看到继承自LinearLayout,再来看下构造函数:
// =========================================================== // Constructors // =========================================================== public PullToRefreshBase(Context context) { super(context); init(context, null); } public PullToRefreshBase(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public PullToRefreshBase(Context context, Mode mode) { super(context); mMode = mode; init(context, null); } public PullToRefreshBase(Context context, Mode mode, AnimationStyle animStyle) { super(context); mMode = mode; mLoadingAnimationStyle = animStyle; init(context, null); }可以发现,这几个构造函数都不约而同的调用了一个方法,PullToRefreshBase#init(context, attrs);今天的主角就是它了,那它都进行了哪些初始操作呢:
@SuppressWarnings("deprecation") private void init(Context context, AttributeSet attrs) { // ①、获取刷新加载的方向 switch (getPullToRefreshScrollDirection()) { case HORIZONTAL: setOrientation(LinearLayout.HORIZONTAL); break; case VERTICAL: default: setOrientation(LinearLayout.VERTICAL); break; } ...... // ②、获取配置的刷新加载模式 if (a.hasValue(R.styleable.PullToRefresh_ptrMode)) { mMode = Mode.mapIntToValue(a.getInteger(R.styleable.PullToRefresh_ptrMode, 0)); } ...... // ③、初始化刷新加载View mRefreshableView = createRefreshableView(context, attrs); // ④、将刷新加载View添加到布局 addRefreshableView(context, mRefreshableView); // ⑤、初始"刷新头部"和"加载外部"布局 mHeaderLayout = createLoadingLayout(context, Mode.PULL_FROM_START, a); mFooterLayout = createLoadingLayout(context, Mode.PULL_FROM_END, a); ...... // ⑥、根据刷新加载模式更新控件 updateUIForMode(); }
省略掉我们暂时不关心的代码,接下来主要分析标注的五段:
①、首先就是抽象的getPullToRefreshScrollDirection()来获取刷新加载的方向,该方法在子类中去实现,也是对应我们在思考中提出的问题一;
②、获取配置的刷新加载模式,有其中Mode为一个内部的枚举,有DISABLED、PULL_FROM_START、PULL_FROM_END、BOTH、MANUAL_REFRESH_ONLY即不允许刷新加载、从头部刷新、从尾部加载、刷新加载都支持、只允许手动刷新加载,对应的在布局中的配置为
<!-- Mode of Pull-to-Refresh that should be used --> <attr name="ptrMode"> <flag name="disabled" value="0x0" /> <flag name="pullFromStart" value="0x1" /> <flag name="pullFromEnd" value="0x2" /> <flag name="both" value="0x3" /> <flag name="manualOnly" value="0x4" /> </attr>
③、createRefreshableView()生成刷新加载View,该方法也是抽象的由子类去实现;
④、在生成刷新加载View后调用了addRefreshableView(),通过名称为加载到View结构上,
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)); }
把刷新加载View添加到FrameLayout上,然后将该FrameLayout 加载到自身LinearLayout上,可见这个名叫mRefreshableViewWrapper 的FrameLayout就是刷新加载View的父View。前面已经提到过,就是对应的我们在思考中提出的问题二;
⑤、初始"刷新头部"和"加载外部"布局,在初始化头部和尾部的时候都是调用的createLoadingLayout()方法,只是传入的参数不同;
protected LoadingLayout createLoadingLayout(Context context, Mode mode, TypedArray attrs) { LoadingLayout layout = mLoadingAnimationStyle.createLoadingLayout(context, mode, getPullToRefreshScrollDirection(), attrs); layout.setVisibility(View.INVISIBLE); return layout; }发现是调用的LoadingAnimationStyle类的createLoadingLayout()方法,接着跟进去:
LoadingLayout createLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) { switch (this) { case ROTATE: default: return new RotateLoadingLayout(context, mode, scrollDirection, attrs); case FLIP: return new FlipLoadingLayout(context, mode, scrollDirection, attrs); } }是根据刷新加载样式不同来生成布局,可以看到默认提供了两种样式,一个是这样的
,另一个是这样的
。
⑥、最后调用了updateUIForMode(),即根据刷新加载的模式来更新UI:
protected void updateUIForMode() { // We need to use the correct LayoutParam values, based on scroll // direction final LinearLayout.LayoutParams lp = getLoadingLayoutLayoutParams(); ...... if (mMode.showHeaderLoadingLayout()) { addViewInternal(mHeaderLayout, 0, lp); } ...... if (mMode.showFooterLoadingLayout()) { addViewInternal(mFooterLayout, lp); } // Hide Loading Views refreshLoadingViewsSize(); ...... }
在这里把头部和尾部 加载到自身LinearLayout上,并隐藏头部和尾部。
至此,怎么生成"刷新头部"、"加载尾部"及"内容区域"并将它们都加载到自身的LinearLayout上就清楚了。
三、结语
在该篇中,我们只是搞清楚了一个问题,就是"刷新头部"、"内容部分"、"加载尾部"是如何初始化及加载到布局上,下篇《AndroidPullToRefresh 分析之三、手势响应》中将主要分析是如何响应手指滑动事件的。
相关文章推荐
- UIViewController
- UIWindow
- Xcode7.2搭UI界面时如何进行横竖屏预览
- ios学习之UISwipeGestureRecognizer手势识别
- 对Map中数据,按value值排序方法
- netty5笔记-线程模型4-MpscLinkedQueue
- netty5笔记-线程模型4-无锁队列MpscLinkedQueue
- 控制Arduino的利器-Windows Remote Arduino
- UIWindows
- iOS 自定义UIButton点击动画特效 —— HERO博客
- UIScrollView实战演练
- 转:js获取json中key所对应的value值
- Item 18: 使用srd::unique_ptr来管理独占所有权的资源
- leetcode(303)Range Sum Query - Immutable js代码实现
- 解决 Assertion failure in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] crash的方法
- continue和pass测试
- java中String、StringBuffer、StringBuilder的区别
- OSChina底层数据库操作的类(QueryHelper)源代码
- 一个短的唯一id生成方法,解决uuid过长的问题
- kafka版本0.8.2.0-Producer Configs之request.required.acks