Android下拉刷新,在目前好多应用被使用到。

比如微博,下拉刷新更多数据。

一般我们在运用的ListView,本身就实现了下拉获取更多数据。只是这个下拉刷新的操作时在listView拉到底端的监听。


对于ListView刷新,我们可以分为两种情况:

1.获取更多的数据,按服务器数据库时间顺序存储入情况,此刻我们是获取是显示在我们应用中的数据更早前的数据,这也是最常见的情况。

比如(微博获取更多信息,就是获取更多更早前的信息,然后动态的添加到已有的数据的下方);

2.获取更多的最新的数据,其实还是一种获取更多的操作方式。但是这里主要考虑到用户的操作习惯了。一般,用户的操作习惯分这么两种

第一种,获取下一页,第二种,类似于网页的F5刷新,停留在当前页面的刷新。

ListView刷新其实类似于网页。如果没用下拉刷新,那么用户得将ListView拖拉到最后(当然也可以是在界面顶端添加一个刷新按钮控件,但是,对于手机这样界面不是很大,这样的设计其实是不应太多的。),如果数据太多,那么用户要下拉到很下面才能执行刷新。而对于大多数用户习惯,获取更多的最新资讯后,希望他添加的时候是在界面最上面的显眼处的。也就是,用户还是喜欢的是懒操作,在同一个可显示界面完成所有操作。那么,下拉刷新是一个不错的设计。

效果图:正常状态


下拉刷新:

基本效果就是这样。

自定义控件代码

[java] view plain copy print ?
  1. /**
  2. *刷新控制view
  3. *
  4. *@authorNono
  5. *
  6. */
  7. publicclassRefreshableViewextendsLinearLayout{
  8. privatestaticfinalStringTAG="LILITH";
  9. privateScrollerscroller;
  10. privateViewrefreshView;
  11. privateImageViewrefreshIndicatorView;
  12. privateintrefreshTargetTop=-60;
  13. privateProgressBarbar;
  14. privateTextViewdownTextView;
  15. privateTextViewtimeTextView;
  16. privateRefreshListenerrefreshListener;
  17. privateStringdownTextString;
  18. privateStringreleaseTextString;
  19. privateLongrefreshTime=null;
  20. privateintlastX;
  21. privateintlastY;
  22. //拉动标记
  23. privatebooleanisDragging=false;
  24. //是否可刷新标记
  25. privatebooleanisRefreshEnabled=true;
  26. //在刷新中标记
  27. privatebooleanisRefreshing=false;
  28. privateContextmContext;
  29. publicRefreshableView(Contextcontext){
  30. super(context);
  31. mContext=context;
  32. }
  33. publicRefreshableView(Contextcontext,AttributeSetattrs){
  34. super(context,attrs);
  35. mContext=context;
  36. init();
  37. }
  38. privatevoidinit(){
  39. //TODOAuto-generatedmethodstub
  40. //滑动对象,
  41. scroller=newScroller(mContext);
  42. //刷新视图顶端的的view
  43. refreshView=LayoutInflater.from(mContext).inflate(R.layout.refresh_top_item,null);
  44. //指示器view
  45. refreshIndicatorView=(ImageView)refreshView.findViewById(R.id.indicator);
  46. //刷新bar
  47. bar=(ProgressBar)refreshView.findViewById(R.id.progress);
  48. //下拉显示text
  49. downTextView=(TextView)refreshView.findViewById(R.id.refresh_hint);
  50. //下来显示时间
  51. timeTextView=(TextView)refreshView.findViewById(R.id.refresh_time);
  52. LayoutParamslp=newLinearLayout.LayoutParams(LayoutParams.FILL_PARENT,-refreshTargetTop);
  53. lp.topMargin=refreshTargetTop;
  54. lp.gravity=Gravity.CENTER;
  55. addView(refreshView,lp);
  56. downTextString=mContext.getResources().getString(R.string.refresh_down_text);
  57. releaseTextString=mContext.getResources().getString(R.string.refresh_release_text);
  58. }
  59. /**
  60. *刷新
  61. *@paramtime
  62. */
  63. privatevoidsetRefreshText(Stringtime){
  64. //TODOAuto-generatedmethodstub
  65. //timeTextView.setText(time);
  66. }
  67. @Override
  68. publicbooleanonTouchEvent(MotionEventevent){
  69. inty=(int)event.getRawY();
  70. switch(event.getAction()){
  71. caseMotionEvent.ACTION_DOWN:
  72. //记录下y坐标
  73. lastY=y;
  74. break;
  75. caseMotionEvent.ACTION_MOVE:
  76. Log.i(TAG,"ACTION_MOVE");
  77. //y移动坐标
  78. intm=y-lastY;
  79. if(((m<6)&&(m>-1))||(!isDragging)){
  80. doMovement(m);
  81. }
  82. //记录下此刻y坐标
  83. this.lastY=y;
  84. break;
  85. caseMotionEvent.ACTION_UP:
  86. Log.i(TAG,"ACTION_UP");
  87. fling();
  88. break;
  89. }
  90. returntrue;
  91. }
  92. /**
  93. *up事件处理
  94. */
  95. privatevoidfling(){
  96. //TODOAuto-generatedmethodstub
  97. LinearLayout.LayoutParamslp=(LayoutParams)refreshView.getLayoutParams();
  98. Log.i(TAG,"fling()"+lp.topMargin);
  99. if(lp.topMargin>0){//拉到了触发可刷新事件
  100. refresh();
  101. }else{
  102. returnInitState();
  103. }
  104. }
  105. privatevoidreturnInitState(){
  106. //TODOAuto-generatedmethodstub
  107. LinearLayout.LayoutParamslp=(LinearLayout.LayoutParams)this.refreshView.getLayoutParams();
  108. inti=lp.topMargin;
  109. scroller.startScroll(0,i,0,refreshTargetTop);
  110. invalidate();
  111. }
  112. privatevoidrefresh(){
  113. //TODOAuto-generatedmethodstub
  114. LinearLayout.LayoutParamslp=(LinearLayout.LayoutParams)this.refreshView.getLayoutParams();
  115. inti=lp.topMargin;
  116. refreshIndicatorView.setVisibility(View.GONE);
  117. bar.setVisibility(View.VISIBLE);
  118. timeTextView.setVisibility(View.GONE);
  119. downTextView.setVisibility(View.GONE);
  120. scroller.startScroll(0,i,0,0-i);
  121. invalidate();
  122. if(refreshListener!=null){
  123. refreshListener.onRefresh(this);
  124. isRefreshing=true;
  125. }
  126. }
  127. /**
  128. *
  129. */
  130. @Override
  131. publicvoidcomputeScroll(){
  132. //TODOAuto-generatedmethodstub
  133. if(scroller.computeScrollOffset()){
  134. inti=this.scroller.getCurrY();
  135. LinearLayout.LayoutParamslp=(LinearLayout.LayoutParams)this.refreshView.getLayoutParams();
  136. intk=Math.max(i,refreshTargetTop);
  137. lp.topMargin=k;
  138. this.refreshView.setLayoutParams(lp);
  139. this.refreshView.invalidate();
  140. invalidate();
  141. }
  142. }
  143. /**
  144. *下拉move事件处理
  145. *@parammoveY
  146. */
  147. privatevoiddoMovement(intmoveY){
  148. //TODOAuto-generatedmethodstub
  149. LinearLayout.LayoutParamslp=(LayoutParams)refreshView.getLayoutParams();
  150. if(moveY>0){
  151. //获取view的上边距
  152. floatf1=lp.topMargin;
  153. floatf2=moveY*0.3F;
  154. inti=(int)(f1+f2);
  155. //修改上边距
  156. lp.topMargin=i;
  157. //修改后刷新
  158. refreshView.setLayoutParams(lp);
  159. refreshView.invalidate();
  160. invalidate();
  161. }
  162. timeTextView.setVisibility(View.VISIBLE);
  163. if(refreshTime!=null){
  164. setRefreshTime(refreshTime);
  165. }
  166. downTextView.setVisibility(View.VISIBLE);
  167. refreshIndicatorView.setVisibility(View.VISIBLE);
  168. bar.setVisibility(View.GONE);
  169. if(lp.topMargin>0){
  170. downTextView.setText(R.string.refresh_release_text);
  171. refreshIndicatorView.setImageResource(R.drawable.refresh_arrow_up);
  172. }else{
  173. downTextView.setText(R.string.refresh_down_text);
  174. refreshIndicatorView.setImageResource(R.drawable.refresh_arrow_down);
  175. }
  176. }
  177. publicvoidsetRefreshEnabled(booleanb){
  178. this.isRefreshEnabled=b;
  179. }
  180. publicvoidsetRefreshListener(RefreshListenerlistener){
  181. this.refreshListener=listener;
  182. }
  183. /**
  184. *刷新时间
  185. *@paramrefreshTime2
  186. */
  187. privatevoidsetRefreshTime(Longtime){
  188. //TODOAuto-generatedmethodstub
  189. }
  190. /**
  191. *结束刷新事件
  192. */
  193. publicvoidfinishRefresh(){
  194. Log.i(TAG,"执行了=====finishRefresh");
  195. LinearLayout.LayoutParamslp=(LinearLayout.LayoutParams)this.refreshView.getLayoutParams();
  196. inti=lp.topMargin;
  197. refreshIndicatorView.setVisibility(View.VISIBLE);
  198. timeTextView.setVisibility(View.VISIBLE);
  199. scroller.startScroll(0,i,0,refreshTargetTop);
  200. invalidate();
  201. isRefreshing=false;
  202. }
  203. /*该方法一般和ontouchEvent一起用
  204. *(non-Javadoc)
  205. *@seeandroid.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
  206. */
  207. @Override
  208. publicbooleanonInterceptTouchEvent(MotionEvente){
  209. //TODOAuto-generatedmethodstub
  210. intaction=e.getAction();
  211. inty=(int)e.getRawY();
  212. switch(action){
  213. caseMotionEvent.ACTION_DOWN:
  214. lastY=y;
  215. break;
  216. caseMotionEvent.ACTION_MOVE:
  217. //y移动坐标
  218. intm=y-lastY;
  219. //记录下此刻y坐标
  220. this.lastY=y;
  221. if(m>6&&canScroll()){
  222. returntrue;
  223. }
  224. break;
  225. caseMotionEvent.ACTION_UP:
  226. break;
  227. caseMotionEvent.ACTION_CANCEL:
  228. break;
  229. }
  230. returnfalse;
  231. }
  232. privatebooleancanScroll(){
  233. //TODOAuto-generatedmethodstub
  234. ViewchildView;
  235. if(getChildCount()>1){
  236. childView=this.getChildAt(1);
  237. if(childViewinstanceofListView){
  238. inttop=((ListView)childView).getChildAt(0).getTop();
  239. intpad=((ListView)childView).getListPaddingTop();
  240. if((Math.abs(top-pad))<3&&
  241. ((ListView)childView).getFirstVisiblePosition()==0){
  242. returntrue;
  243. }else{
  244. returnfalse;
  245. }
  246. }elseif(childViewinstanceofScrollView){
  247. if(((ScrollView)childView).getScrollY()==0){
  248. returntrue;
  249. }else{
  250. returnfalse;
  251. }
  252. }
  253. }
  254. returnfalse;
  255. }
  256. /**
  257. *刷新监听接口
  258. *@authorNono
  259. *
  260. */
  261. publicinterfaceRefreshListener{
  262. publicvoidonRefresh(RefreshableViewview);
  263. }
  264. }

此控件自定义实现一个线性布局,内部包含一个第一个子控件,刷新显示的View。

因为对于ListView下拉刷新的例子网上挺多的,上次我朋友也做,说特么弄了一个礼拜发现一个问题,listview里面条目太少时,刷新的view就会显示出来。

我没具体看过那个代码,也不知道到底什么情况。

自个定义的稍微用了点小技巧。即,我将刷新view的topMargin设置为了该view的高度的负数,那么,他就刚好隐藏起来了。

对于上面那个对于条目太少而造成刷新的view显示的bug有所解决。

[java] view plain copy print ?
  1. @Override
  2. publicbooleanonTouchEvent(MotionEventevent){
  3. inty=(int)event.getRawY();
  4. switch(event.getAction()){
  5. caseMotionEvent.ACTION_DOWN:
  6. //记录下y坐标
  7. lastY=y;
  8. break;
  9. caseMotionEvent.ACTION_MOVE:
  10. Log.i(TAG,"ACTION_MOVE");
  11. //y移动坐标
  12. intm=y-lastY;
  13. if(((m<6)&&(m>-1))||(!isDragging)){
  14. doMovement(m);
  15. }
  16. //记录下此刻y坐标
  17. this.lastY=y;
  18. break;
  19. caseMotionEvent.ACTION_UP:
  20. Log.i(TAG,"ACTION_UP");
  21. fling();
  22. break;
  23. }
  24. returntrue;
  25. }
  26. /*该方法一般和ontouchEvent一起用
  27. *(non-Javadoc)
  28. *@seeandroid.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
  29. */
  30. @Override
  31. publicbooleanonInterceptTouchEvent(MotionEvente){
  32. //TODOAuto-generatedmethodstub
  33. intaction=e.getAction();
  34. inty=(int)e.getRawY();
  35. switch(action){
  36. caseMotionEvent.ACTION_DOWN:
  37. lastY=y;
  38. break;
  39. caseMotionEvent.ACTION_MOVE:
  40. //y移动坐标
  41. intm=y-lastY;
  42. //记录下此刻y坐标
  43. this.lastY=y;
  44. if(m>6&&canScroll()){
  45. returntrue;
  46. }
  47. break;
  48. caseMotionEvent.ACTION_UP:
  49. break;
  50. caseMotionEvent.ACTION_CANCEL:
  51. break;
  52. }
  53. returnfalse;
  54. }

控件使用:

[html] view plain copy print ?
  1. <PREclass=htmlname="code"><com.xxx.xxxx.view.RefreshableViewandroid:orientation="vertical"android:id="@+id/refresh_root"
  2. android:layout_width="fill_parent"android:layout_height="wrap_content"
  3. xmlns:android="http://schemas.android.com/apk/res/android">
  4. <ListViewandroid:id="@+id/def_list"android:layout_width="fill_parent"
  5. android:scrollbars="none"android:fadingEdge="none"
  6. android:layout_height="wrap_content"android:scrollingCache="false">
  7. </ListView>
  8. </com.xxxx.xxxxx.view.RefreshableView></PRE><PREstyle="BACKGROUND-COLOR:rgb(255,255,255)"class=htmlname="code"><PREstyle="BACKGROUND-COLOR:rgb(255,255,255)"class=htmlname="code"></PRE>
  9. <P></P>
  10. <P></P>
  11. <P>即,我的listview是以该控件的第二个子view加入进去。此刻又会遇到一个问题:我在界面执行下拉时,应用如何分辨我是执行的RefreshableView下拉刷新操作,还是listview下拉操作。这个问题一开始挺悲剧的,就是当我的listview中数据挺多,那我手势一网上滑,此刻操作不会出现冲突,因为刷新View监听的下滑事件监听;然后此刻listview滑到了底部,我要回到listview顶部去,就得执行向下滑操作,那么这时的操作就和刷新view中下滑,下拉刷新监听冲突。后来发现了view中两个函数:子控件截取事件函数。具体来说是就是用的点击屏幕,touch事件会先被onInterceptTouchEvent捕捉,子view先做处理,然后根据true和false,才判断是否截取事件交给父View处理。那么我们就可以在onInterceptTouchEvent做了预处理,更具判断listview是佛在最底部,可下滑,来判断是佛让子view来截取处理该touch事件。具体判断看canScroll();同样的考虑到ScrollView类似有listview的情况,也做了处理,因此该控件支持包含listview和scrollview。实现代码基本如上,内部可能还有挺多的bug,但是目前我应用上实现暂没发现。最后感谢网上的可刷新代码demo,以及sina微博可刷新控件代码以及网易应用可刷新控件代码。</P>
  12. <P></P>
  13. <P></P>
  14. <P></P>
  15. <P></P>
  16. <PRE></PRE>
  17. <PRE></PRE>
  18. <PRE></PRE>
  19. <PRE></PRE>
  20. <PRE></PRE>
  21. </PRE>

10
0

查看评论

13楼 DaweiKoo 2013-04-28 10:18发表 [回复] [引用] [举报]
新手学习。感谢分享。
12楼 Rockey723 2013-03-14 13:40发表 [回复] [引用] [举报]
大神厉害,顶
Re: Rockey723 2013-03-14 13:49发表 [回复] [引用] [举报]
回复Rockey723:非常的齐全
11楼 _Zero 2013-01-24 14:05发表 [回复] [引用] [举报]
学习下!!!!!
10楼 枫叶雅少 2013-01-24 08:54发表 [回复] [引用] [举报]

更多相关文章

  1. Android(安卓)View分区域点击实现方案——1.根据坐标范围
  2. Android(安卓)RecyclerView删除多个选中的item 及 局部刷新
  3. Android(安卓)补间动画之平移动画TranslateAnimation
  4. Android(安卓)基于坐标的图形开发
  5. Android变形(Transform)之Matrix用法
  6. android 屏幕坐标总结
  7. Android画布canvas rotate,translate的理解
  8. Android实现仿QQ登录可编辑下拉菜单
  9. Android实现滑动的七种方法实践

随机推荐

  1. RadioGroup&RadioButton小技巧
  2. Flutter基础-Preparing an IOS/Android(
  3. android图片压缩处理,并保存
  4. Android(安卓)GPS Location with Listene
  5. 安装 ADT 插件
  6. Ubuntu10.04安装JDK5
  7. Android权限 (代码区2)
  8. Android(安卓)NeedProxy
  9. Flutter Weekly Issue 61
  10. Install Android(安卓)NDK No.1