美文网首页
ListView上拉刷新

ListView上拉刷新

作者: 陌上疏影凉 | 来源:发表于2017-03-13 21:53 被阅读50次

    上拉刷新效果是很多app都具备的功能,每次只加载少量的数据,等这些数据全部展示完后,再展示下一组数据,可以很好地避免一次加载过多数据问题,特别是涉及到网络请求时。先看一下效果:

    test.gif

    自定义ListView###

    要实现这样的效果,首先定义一个LoadListView继承自ListView,实现构造方法

     public LoadListView(Context context) {
            super(context);
            initView(context);
        }
    
        public LoadListView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initView(context);
        }
    
        public LoadListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView(context);
        }
    

    然后创建initView(Context context)方法,添加一个FooterView

     private void initView(Context context) {
            footView = LayoutInflater.from(context).inflate(R.layout.foot_view, null);
            this.addFooterView(footView);
      }
    

    再实现AbsListView.OnScrollListener接口,为LoadListView添加滚动事件监听,实现该接口需要实现以下两个方法:

    • public void onScrollStateChanged(AbsListView view, int scrollState)

      scrollState有三种状态,分别是SCROLL_STATE_IDLESCROLL_STATE_TOUCH_SCROLLSCROLL_STATE_FLING
      SCROLL_STATE_IDLE是当屏幕停止滚动时
      SCROLL_STATE_TOUCH_SCROLL是当用户在以触屏方式滚动屏幕并且手指仍然还在屏幕上时(The user is scrolling using touch, and their finger is still on the screen)
      SCROLL_STATE_FLING是当用户由于之前划动屏幕并抬起手指,屏幕产生惯性滑动时(The user had previously been scrolling using touch and had performed a fling)

    • public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)

    firstVisibleItem表示在当前屏幕显示的第一个listItem在整个listView里面的位置(下标从0开始) **
    visibleItemCount表示在现时屏幕可以见到的ListItem
    (部分显示的ListItem也算)**总数
    totalItemCount表示ListView的ListItem总数 (包括FooterView和HeaderView的数目)

    比如下面的图:

    这是打印的日志信息:


    • firstVisible是第一个可见元素下标,这里是第2个(虽然被挡住了)
    • visibleItem是当前可见的数目,从2到10一共9个
    • totalItem是总共有46条数据(包括一个FooterView)
    • lastItem是自己定义的变量,表示最后一个可见元素下标
    • adapterItemCount自己定义的变量,表示总共45条数据(不包括FooterView)

    下面实现该接口,首先在initView方法中注册监听

    private void initView(Context context) {
        ......
        this.setOnScrollListener(this);
    }
    

    然后让LoadListView实现AbsListView.OnScrollListener

    public class LoadListView extends ListView implements AbsListView.OnScrollListener 
    

    接着实现相应的方法:

     @Override
     public void onScrollStateChanged(AbsListView view, int scrollState) {
         if(mLastItemCount == mAdapterItemCount
                 && scrollState == NumberPicker.OnScrollListener.SCROLL_STATE_IDLE){
             //加载数据
             if(!isLoading) {
                 isLoading = true;
                 mLoadListener.onLoad();
             }
         }
     }
     @Override
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
         mAdapterItemCount = totalItemCount - 1;
         mLastItemCount = firstVisibleItem + visibleItemCount - 1;
        
         if(mLastItemCount < mAdapterItemCount){
             isLoading = false;
         }
     }
    

    当最后一个可见元素等于数据条数的时候,换句话说,当footerview可见时,并且滑动状态处于滑动停止,那么向外提供一个接口,实现加载数据的操作,为了一次只加载一页数据,所以需要用isLoading来限制只加载一次。不然会出现,在加载数据时不断滑动加载多次数据的情况。当加载数据完成后,一般会调用ListView的adapter的adapter.notifyDataSetChanged()方法,这时,mAdapterItemCount即数据条数会增加,导致mLastItemCount < mAdapterItemCount,从而将isLoading状态置为false,准许下一次加载数据。

    MainActivity中onLoad()方法的实现:

       handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    for(int i=0;i<5;i++) {
                        mItemList.add(new ItemBean("item" + count , R.drawable.icon2));
                        count++;
                    }
                    adapter.notifyDataSetChanged();
                }
            },3000);
    

    这里一般是网络请求下一页的数据,这里直接用延时程序代替了。

    所有源码###

    MainActivity

    public class MainActivity extends AppCompatActivity implements LoadListView.LoadListener {
        private List<ItemBean> mItemList;
        private LoadListView listView;
        private MyAdapter adapter;
    
        int count = 0;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            listView = (LoadListView) findViewById(R.id.list_view);
    
            mItemList = new ArrayList<>();
            for(int i=0;i<20;i++) {
                mItemList.add(new ItemBean("item" + count , R.drawable.icon1));
                count++;
            }
            adapter = new MyAdapter();
            listView.setAdapter(adapter);
            listView.setLoadListener(this);
    
        }
        private Handler handler = new Handler();
    
        @Override
        public void onLoad() {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    for(int i=0;i<5;i++) {
                        mItemList.add(new ItemBean("item" + count , R.drawable.icon2));
                        count++;
                    }
                    adapter.notifyDataSetChanged();
                }
            },3000);
    
        }
    
        class MyAdapter extends BaseAdapter {
    
            @Override
            public int getCount() {
    //        Log.d("mytag",mItemList.size()+"");
                return mItemList.size();
    
            }
    
            @Override
            public Object getItem(int position) {
    //            Log.d("mytag", mItemList.get(position).toString());
                return mItemList.get(position);
            }
    
            @Override
            public long getItemId(int position) {
                return position;
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder holder;
                if (convertView == null) {
                    holder = new ViewHolder();
                    convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);
                    holder.iv = (ImageView) convertView.findViewById(R.id.iv);
                    holder.tv = (TextView) convertView.findViewById(R.id.tv);
                    convertView.setTag(holder);
                } else {
                    holder = (ViewHolder) convertView.getTag();
                }
    
                ItemBean bean = mItemList.get(position);
                Log.d("mytag", bean.toString());
                holder.tv.setText(bean.getText());
                holder.iv.setBackgroundResource(bean.getImgId());
                return convertView;
            }
    
            class ViewHolder {
                ImageView iv;
                TextView tv;
            }
        }
    }
    
    
    

    LoadListView

    public class LoadListView extends ListView implements AbsListView.OnScrollListener {
        
        private View footView;
        private int mLastItemCount;
        private int mAdapterItemCount;
        private boolean isLoading = false;
    
        public LoadListView(Context context) {
            super(context);
            initView(context);
        }
    
        public LoadListView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initView(context);
        }
    
        public LoadListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView(context);
        }
    
        private void initView(Context context) {
            footView = LayoutInflater.from(context).inflate(R.layout.foot_view, null);
            this.addFooterView(footView);
            this.setOnScrollListener(this);
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if(mLastItemCount == mAdapterItemCount
                    && scrollState == NumberPicker.OnScrollListener.SCROLL_STATE_IDLE){
                //加载数据
                if(!isLoading) {
                    isLoading = true;
                    if(mLoadListener != null) {
                        mLoadListener.onLoad();
                    }
                    Log.d(TAG, "onScrollStateChanged: " + "onLoad()");
                }
    
            }
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            //计算数据条数,减去 
            mAdapterItemCount = totalItemCount - 1;
            mLastItemCount = firstVisibleItem + visibleItemCount - 1;
    
            if(mLastItemCount < mAdapterItemCount){
                isLoading = false;
            }
        }
    
        private LoadListener mLoadListener;
    
        public void setLoadListener(LoadListener loadListner){
            this.mLoadListener = loadListner;
        }
    
        public void setAdapterCount(int count) {
            this.mAdapterItemCount = count;
        }
    
        public void setIsLoading(boolean isLoading) {
            this.isLoading = isLoading;
        }
    
        public interface LoadListener{
            void onLoad();
        }
    
    }
    

    ItemBean

    public class ItemBean {
        private String text;
        private int imgId;
    
        public void setText(String text) {
            this.text = text;
        }
    
        public void setImgId(int imgId) {
            this.imgId = imgId;
        }
    
        public String getText() {
    
            return text;
        }
    
        public int getImgId() {
            return imgId;
        }
    
        public ItemBean(String text, int imgId) {
    
            this.text = text;
            this.imgId = imgId;
        }
    
        @Override
        public String toString() {
            return "ItemBean{" +
                    "text='" + text + '\'' +
                    ", imgId=" + imgId +
                    '}';
        }
    }
    

    参考资料:http://www.linuxidc.com/Linux/2014-05/101540.htm

    相关文章

      网友评论

          本文标题:ListView上拉刷新

          本文链接:https://www.haomeiwen.com/subject/nkltnttx.html