ListView上拉刷新

上拉刷新效果是很多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的数目)

比如下面的图:

ListView上拉刷新_第1张图片

这是打印的日志信息:


ListView上拉刷新_第2张图片
  • 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 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上拉刷新)