zoukankan      html  css  js  c++  java
  • ListView实现下拉刷新(三)实现下拉刷新

     

          该准备的东西都已经准备好了。在这篇文章里,我们就开始实现下拉刷新功能吧。

     

    一、大体的逻辑分析

     

          我们来简单分析一下需要做的逻辑吧。首先分析头布局有几种状态。不下拉时,为正常状态,此时头布局隐藏。下拉到一定高度,提示信息变为“下拉刷新”,箭头朝下,此为下拉状态。再往下拉,提示信息变为“松开刷新”,箭头朝上,此为提示刷新状态。而此时松开手指,则执行刷新操作,头布局变为进度条显示,箭头消失,此为正在刷新状态。相反的,其他状态下松开手指,都不执行刷新操作,应该将头布局恢复到正常状态。因为可确定头布局的状态有四种。

          我们根据这四种状态,确定我们要做的事情。要监听ListView的滚动,故要实现OnScrollListener接口。还要监听手指触摸事件,根据手指的下拉移动来改变头布局的显示效果,根据手指的抬起来判断是否进行刷新操作,因为要实现onTouchEvent方法。也就是说,头布局状态的改变应该随着手指的移动而改变,因此在onTouchEvent里面我们要实现上面分析的四种状态的改变。当然,状态改变就意味着头布局显示效果的改变,这里可以嵌套在onTouchEvent方法里面。但考虑到避免方法臃肿,以及其他地方可能也需要改变头布局界面,比如数据加载完成后等情况,因此专门将头布局界面的改变抽取出来,凝聚为一个方法。

          然后就是数据刷新,刷新操作要在MyListView里执行,但是数据要在MainActivity中获取。老规矩,用接口回调即可。

          好了,基本上大体的逻辑就这么多了。下面我们将上面的分析转化为代码。

     

    二、代码编写

     

          废话我就不多说了,上面的分析很清楚了。继续完善MyListView即可。代码如下:

      1 package com.fuly.load;
      2 
      3 import android.content.Context;
      4 import android.util.AttributeSet;
      5 import android.view.LayoutInflater;
      6 import android.view.MotionEvent;
      7 import android.view.View;
      8 import android.view.ViewGroup;
      9 import android.widget.AbsListView;
     10 import android.widget.AbsListView.OnScrollListener;
     11 import android.widget.ImageView;
     12 import android.widget.ListView;
     13 import android.widget.ProgressBar;
     14 import android.widget.TextView;
     15 
     16 public class MyListView extends ListView implements OnScrollListener{
     17     
     18     private View header;//头布局
     19     
     20     private int headerHeight;//头布局自身的高度
     21     
     22     private int scrollState;//当前滚动状态
     23     private int firstVisibleItem;//当前可见的第一个item
     24     private int startY;//刚开始触摸屏幕时的Y值
     25     
     26     private int curState = 0;//当前header状态,默认为0
     27     private final int NORMAL = 0;//正常状态
     28     private final int PULL = 1;//状态下拉
     29     private final int RELEASE = 2;//提示刷新状态
     30     private final int RELEASING = 3;//状态正在刷新
     31     
     32     private boolean canPull = false;//是否可以执行下拉操作
     33     
     34     private refresfListener mListener;//回调接口
     35     
     36 
     37     //三个构造方法都要重写
     38     public MyListView(Context context) {
     39         super(context);
     40         initView( context);
     41         
     42     }
     43     public MyListView(Context context, AttributeSet attrs) {
     44         super(context, attrs);
     45         initView( context);
     46         
     47     }
     48     public MyListView(Context context, AttributeSet attrs, int defStyle) {
     49         super(context, attrs, defStyle);
     50         initView( context);
     51     
     52     }
     53     
     54     //定义回调接口
     55     public interface refresfListener{
     56         void refresh();
     57     }
     58     public void setOnRefreshListener(refresfListener listener){
     59         this.mListener = listener;
     60     }
     61     
     62     
     63     public void initView(Context context){
     64         
     65         header = LayoutInflater.from(context).inflate(R.layout.header, null);
     66         notifyView(header);
     67         headerHeight = header.getMeasuredHeight();//获取header的高度
     68 
     69 //        headerHeight = header.getHeight();
     70         paddingTop(-headerHeight);
     71         //将头布局加进去
     72         this.addHeaderView(header);
     73         
     74         this.setOnScrollListener(this);
     75     }
     76 
     77     
     78     
     79     
     80     /**
     81      * 该方法为通知父布局,子布局view的宽度和高度
     82      * @param view:子布局
     83      */
     84     private void notifyView(View view){
     85         
     86         ViewGroup.LayoutParams p = view.getLayoutParams();
     87         
     88         if(p == null){
     89             p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
     90             
     91         }
     92         
     93         //spec表示当前子view左右边距,padding表示子view的左右内边距
     94         //childDimension:子view的宽度
     95         int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
     96         
     97         int height;
     98         int tempHeight = p.height;
     99         if(tempHeight>0){
    100             //子布局高度不为空,需要填充这个布局
    101             height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
    102         }else{
    103             //高度为0,则不需要填充
    104             height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
    105         }
    106         
    107         //然后告诉父布局,子布局的高度和宽度
    108         view.measure(width, height);    
    109     }
    110     
    111     
    112     //该方法设定header的paddingTop
    113     private void paddingTop(int pt){
    114         header.setPadding(header.getPaddingLeft(), pt, header.getPaddingRight(), header.getPaddingBottom());
    115         header.invalidate();
    116     }
    117     
    118     
    119     
    120 
    121     /***
    122      * 监听当前滚动状态
    123      * scrollState:当前滚动状态
    124      */
    125     public void onScrollStateChanged(AbsListView view, int scrollState) {
    126         //记录当前的滚动状态
    127         this.scrollState = scrollState;
    128         
    129     }
    130     
    131     /***
    132      * 监听当前滚动的item
    133      * firstVisibleItem:当前可见的第一个item
    134      * visibleItemCount:当前共有多少个item可见
    135      * totalItemCount:总共有多少个item
    136      * 
    137      */
    138     public void onScroll(AbsListView view, int firstVisibleItem,
    139             int visibleItemCount, int totalItemCount) {
    140         
    141         this.firstVisibleItem = firstVisibleItem;
    142         
    143         
    144     }
    145     
    146     
    147     //触屏事件
    148     public boolean onTouchEvent(MotionEvent ev) {
    149         
    150         switch(ev.getAction()){
    151              //手指落到屏幕上时
    152         case MotionEvent.ACTION_DOWN:
    153             //如果当前可见的第一个item为第0号,说明ListView位于顶端,可以执行下拉刷新
    154             if(firstVisibleItem == 0){
    155                 canPull = true;
    156                 startY = (int) ev.getY();
    157             }
    158             
    159             break;
    160             //手指在屏幕上拖动时
    161         case MotionEvent.ACTION_MOVE:
    162             if(canPull){
    163                 touchMove(ev);
    164             }
    165             break;
    166             //手指离开屏幕时
    167         case MotionEvent.ACTION_UP:
    168             canPull = false;
    169             if(curState == RELEASE){
    170                 curState = RELEASING;
    171                 refreshHeaderByState();
    172                 //这里添加刷新数据的逻辑
    173                 mListener.refresh();
    174             }else{
    175                 curState = NORMAL;
    176                 refreshHeaderByState();
    177                 paddingTop(-headerHeight);
    178             }
    179             
    180             break;
    181         }
    182         
    183         return super.onTouchEvent(ev);
    184     }
    185     
    186     /**
    187      * 该方法根据触摸屏幕滑动来改变STATE,即改变当前状态
    188      * @param ev
    189      */
    190     private void touchMove(MotionEvent ev) {
    191         
    192         int tempY = (int) ev.getY();
    193         int space = tempY -startY;//移动的距离
    194         int topdding = space-headerHeight;
    195         paddingTop(topdding);//即时设定头布局的隐藏高度
    196         if(space>headerHeight&&space<headerHeight+50&&scrollState == SCROLL_STATE_TOUCH_SCROLL){
    197              curState = PULL;//设定为下拉状态
    198              refreshHeaderByState();
    199         }
    200         if(space>headerHeight+50){
    201             curState = RELEASE;//设定为提示刷新状态
    202              refreshHeaderByState();
    203         }
    204         
    205         if(space<headerHeight){
    206             curState = NORMAL;//设定为正常状态
    207              refreshHeaderByState();
    208         }
    209         
    210         
    211     }
    212     
    213     
    214     /**
    215      * 根据当前状态更改header的显示界面
    216      * 
    217      */
    218     private void refreshHeaderByState( ){
    219         ProgressBar pb = (ProgressBar) header.findViewById(R.id.progress_bar);
    220         ImageView img = (ImageView) header.findViewById(R.id.img_arrow);
    221         TextView tv = (TextView) header.findViewById(R.id.textinfo);
    222         
    223         switch(curState){
    224         
    225             case NORMAL:
    226                 pb.setVisibility(View.GONE);
    227                 img.setVisibility(View.VISIBLE);
    228                 img.setImageResource(R.drawable.down_arrow);
    229                 tv.setText("下拉刷新");
    230             break;
    231             case PULL:
    232                 pb.setVisibility(View.GONE);
    233                 img.setVisibility(View.VISIBLE);
    234                 img.setImageResource(R.drawable.down_arrow);
    235                 tv.setText("下拉刷新");
    236                 break;
    237             case RELEASE:
    238                 pb.setVisibility(View.GONE);
    239                 img.setVisibility(View.VISIBLE);
    240                 img.setImageResource(R.drawable.up_arrow);
    241                 tv.setText("松开刷新");
    242                 break;
    243             case RELEASING:
    244                 pb.setVisibility(View.VISIBLE);
    245                 img.setVisibility(View.GONE);
    246                 tv.setText("正在刷新");
    247                 break;
    248             
    249             
    250         }
    251         
    252     }
    253     
    254     //数据刷新完成后的操作
    255     public void refreshFinish(){
    256         
    257         curState = NORMAL;
    258         paddingTop(-headerHeight);
    259         refreshHeaderByState();
    260     }
    261     
    262     
    263     
    264 }

     

          接下来就是MainActivity中的代码了。如下:

     

     1 package com.fuly.load;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 import com.fuly.load.MyListView.refresfListener;
     7 
     8 import android.os.Bundle;
     9 import android.os.Handler;
    10 import android.app.Activity;
    11 
    12 public class MainActivity extends Activity implements refresfListener{
    13     
    14     private MyListView lv;
    15     private List<MyData>  mDatas = new ArrayList<MyData>();
    16     private MyAdapter mAdapter;
    17 
    18 
    19     protected void onCreate(Bundle savedInstanceState) {
    20         super.onCreate(savedInstanceState);
    21         setContentView(R.layout.activity_main);
    22         
    23         initData();//该方法初始化数据
    24         lv = (MyListView) findViewById(R.id.list_view);
    25         lv.setOnRefreshListener(this);//设定回调接口
    26         mAdapter = new MyAdapter(this, mDatas);
    27         lv.setAdapter(mAdapter);
    28         
    29         
    30     }
    31 
    32 
    33     /**
    34      * 该方法初始化数据,即提供初始的素材
    35      */
    36     private void initData() {
    37         for(int i = 0;i<12;i++){
    38             MyData md = new MyData("你好,我是提前设定的");
    39             mDatas.add(md);
    40         }
    41         
    42     }
    43       /**
    44      * 提供刷新数据
    45      */
    46     private void getRefreshData() {
    47         for(int i = 0;i<3;i++){
    48             MyData md = new MyData("你好,我是刷新进来的");
    49             mDatas.add(i, md);
    50         }
    51         
    52     }
    53 
    54 
    55     //重写回调方法
    56     public void refresh() {
    57         
    58         //在这里之所以使用Handler,是想让操作延迟,这样子效果看起来更
    59         //清晰,实际项目中,是 不需要的
    60         Handler mHandler = new Handler();
    61         mHandler.postDelayed(new Runnable(){
    62 
    63             @Override
    64             public void run() {
    65                 //获得刷新数据
    66                 getRefreshData();
    67                 //刷新ListView
    68                 mAdapter.notifyDataSetChanged();
    69                 //lv.setSelection(mDatas.size()-1);
    70                 
    71                 //刷新后
    72                 lv.refreshFinish();
    73                 
    74             }
    75             
    76         }, 5000    );
    77         
    78         
    79         
    80     }
    81 }

          好了,快快运行下程序,体验下拉刷新的效果吧。至此,ListView实现下拉刷新,我们讲解完毕了。

  • 相关阅读:
    java程序员必读的书籍(适合于本人)
    面试第三天
    sql常用的函数(持续更新中)
    linux 常用命令
    drf的Response返回字符串有问题
    celery pip仓库上的代码有问题 请使用git上最新版
    PyCrypto已放弃维护 请使用PyCryptodome
    django+celery实现异步任务
    利用Oh-My-Zsh打造你的超级终端---待排版
    pycharm搭配docker本地调试
  • 原文地址:https://www.cnblogs.com/fuly550871915/p/4867231.html
Copyright © 2011-2022 走看看