针对自定义组件上拉刷新下拉加载更多PullToRefreshView的分析(一)


分类: Android开发学习实践   547人阅读  评论(3)  收藏  举报

首先PullToRefreshView是一个上拉刷新下拉加载的一个自定义组件,它支持三种view,ListView,GridView和ScrollView的刷新操作,这里就针对其中自己觉得比较有用的一部分进行分析。代码会放在下面。在下有的地方也不是很懂,如果有不对的地方请指正。先给个图找找感觉。

 转载请注明出处:https://i-blog.csdnimg.cn/blog_migrate/d8bb591129fe273f5b89808a01c7f611.png



在TestListView.java里面有这样一段代码,这里TestListView这个类继承了ListActivity并且实现了在PullToRefreshView类中的OnHeaderRefreshListener,OnFooterRefreshListener监听接口,下面就是重写了OnHeaderRefreshListener中的onHeaderRefresh方法,并用View.PostDelayed(Runnabe,long)在1秒后启动后台线程在UI上进行上拉刷新的view的更改。这一步看起来简单,但是背后是

加载PullToRefreshView组件以及触摸屏幕发生一些操作,其中涉及两个refreshview的加载及变化操作,触摸手势判断监听,动画以及平滑拉动等操作,下面自己觉得重要不好懂的地方的分析下。

[java]  view plain copy
  1. @Override  
  2. public void onHeaderRefresh(PullToRefreshView view) {  
  3.     mPullToRefreshView.postDelayed(new Runnable() {  
  4.           
  5.         @Override  
  6.         public void run() {  
  7.             //设置更新时间  
  8.             //mPullToRefreshView.onHeaderRefreshComplete("最近更新:01-23 12:01");  
  9.             mPullToRefreshView.onHeaderRefreshComplete();  
  10.         }  
  11.     },1000);  
  12.       
  13. }  

首先来看下这个最关键的自定义组件类PullToRefreshView,它继承了LinearLayout这个ViewGroup子类,为什么要继承这个类呢,首先我们去掉中间那些列表,一头一尾剩下两个refreshView被一个ViewGroup给包裹起来,这就是可以进行复用的部分了,以后不管是那个app需要这个刷新组件,用PullToRefreshView去代替LinearLayout这样的布局组件就行了,然后实现onHeaderRefresh和onFooterRefresh就行了。

PullToRefreshView这个组件大概有600行代码,前面是一堆要定义这个组件的其他组件和参数的申明定义。接下来在构造器中进行初始化,构造器中调用了一个init方法。

[java]  view plain copy
  1. private void init() {  
  2.     // Load all of the animations we need in code rather than through XML  
  3.     mFlipAnimation = new RotateAnimation(0, -180,  
  4.             RotateAnimation.RELATIVE_TO_SELF, 0.5f,  
  5.             RotateAnimation.RELATIVE_TO_SELF, 0.5f);  
  6.     mFlipAnimation.setInterpolator(new AccelerateDecelerateInterpolator());  
  7.     mFlipAnimation.setDuration(250);  
  8.     mFlipAnimation.setFillAfter(true);  
  9.     mReverseFlipAnimation = new RotateAnimation(-1800,  
  10.             RotateAnimation.RELATIVE_TO_SELF, 0.5f,  
  11.             RotateAnimation.RELATIVE_TO_SELF, 0.5f);  
  12.     mReverseFlipAnimation.setInterpolator(new AccelerateDecelerateInterpolator());  
  13.     mReverseFlipAnimation.setDuration(100);  
  14.     mReverseFlipAnimation.setFillAfter(true);  
  15.   
  16.     mInflater = LayoutInflater.from(getContext());  
  17.     // header view 在此添加,保证是第一个添加到linearlayout的最上端  
  18.     addHeaderView();  
  19. }  
这里关键部分就是旋转动画RotateAnimation类,我们看见的那个下拉时会动的箭头就是这个地方的作用,在你进行下拉操作时那个箭头的ImageView以动画方式启动了这个动画旋转类。

[java]  view plain copy
  1. mHeaderImageView.startAnimation(mFlipAnimation);  
接着init最后一句代码addHeaderView()把头部的refreshView给添加进来。

[java]  view plain copy
  1. private void addHeaderView() {  
  2.     // header view  
  3.     mHeaderView = mInflater.inflate(R.layout.refresh_header, thisfalse);  
  4.   
  5.     mHeaderImageView = (ImageView) mHeaderView  
  6.             .findViewById(R.id.pull_to_refresh_image);  
  7.     mHeaderTextView = (TextView) mHeaderView  
  8.             .findViewById(R.id.pull_to_refresh_text);  
  9.     mHeaderUpdateTextView = (TextView) mHeaderView  
  10.             .findViewById(R.id.pull_to_refresh_updated_at);  
  11.     mHeaderProgressBar = (ProgressBar) mHeaderView  
  12.             .findViewById(R.id.pull_to_refresh_progress);  
  13.     // header layout  
  14.     measureView(mHeaderView);  
  15.     mHeaderViewHeight = mHeaderView.getMeasuredHeight();  
  16.     LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,  
  17.             mHeaderViewHeight);  
  18.     // 设置topMargin的值为负的header View高度,即将其隐藏在最上方  
  19.     params.topMargin = -(mHeaderViewHeight);  
  20.     // mHeaderView.setLayoutParams(params1);  
  21.     addView(mHeaderView, params);  
  22.   
  23. }  
其中关键代码在最后几句,measureView(mHeaderView)对子控件mHeaderView进行了测量,然后才能把这个子控件塞进 PullToRefreshView,说得通熟易懂点,就是当你自定义组件时,如果要往父控件里面放入其他子控件,那么你的父控件会首先问你子控件需要多大一块地方,你给了这个宽高之后我才能把你放进来,measureView(View child)中最后一句child.measure(childWidthSpec, childHeightSpec);就是设置了子控件的宽高,到时候父控件就会给你那么大块地方。需要注意的是,View.measure这个方法中,实际上调用了View.onMeasure这个方法,而这个方法才是自定义组件中经常会重写的一个测量方法,具体可以搜搜网上的用法。

上面的代码段中还有一句params.topMargin = -(mHeaderViewHeight);这里就是为什么当你下拉时才会看见那个刷新view,是因为这个头部刷新条将自己隐藏起来了,做法就是子view与父view上边界的距离等于子view自身高度的负值,这样就可以正好隐藏自己。接下里就把这个上拉刷新view添加到父view中,然后下拉加载的view也是几乎同样的道理,唯一的不同点在于,由于是线性布局可以直接添加,只要AdapterView的高度是MATCH_PARENT,那么footer view就会被添加到最后,并隐藏。

addFooterView没有直接在init方法中,而是放到了下面的方法中。

[java]  view plain copy
  1. @Override  
  2. protected void onFinishInflate() {  
  3.     super.onFinishInflate();  
  4.     // footer view 在此添加保证添加到linearlayout中的最后  
  5.     addFooterView();  
  6.     initContentAdapterView();  
  7. }  

这里重写了View.onFinishInflate方法,当View和它的所有子对象从XML中导入之后,此方法才会被回调,这样,前面前面的顺序都排好了,这里再添加个foot refreshView,就能保证把它添加到最后,不然有可能添加到AdapterView的前面。

接着说,下面的initContentAdapterView方法是对列表的初始化,就不多说了。

上面将各个组件都初始化并测量加载之后,就要开始各种监听以及判断处理了,我们第二篇再接着讲。下面先附上代码,不好意思加了一分竟然不能编辑改下分数,大家也可以直接搜下PullToRefreshView看看哪里有没有免费的下载,懒得改了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值