ListView下拉刷新和上拉加载原理

来源:互联网 发布:程序员为什么叫程序猿 编辑:程序博客网 时间:2024/06/04 10:07
ListView的下拉刷新逻辑:
一、获取ListView的头布局的高度并通过给头布局setPading方法,将头布局隐藏
二、重写ListView的onTouchEvent方法计算出滑动的偏移量dy
三、通过比较偏移量和头布局的高度,进行UI的修改
ListView上拉加载逻辑:
一、获取ListView的脚布局的高度并通过setPading方法,将头布局隐藏
二、调用ListView的setOnScrollListener方法,重写两个方法
1、onScrollStateChanged
当滑动状态是静止状态,并且最后一个条目是脚布局
的时候,显示脚布局,然后加载下一页数据,并修改UI

2、onScroll

接下来直接看代码:

public class RefreshListVeiw extends ListView implements AbsListView.OnScrollListener {    public static final int STATE_PULL_TO_REFRESH    = 0;//下拉刷新    public static final int STATE_RELEASE_TO_REFRESH = 1;//松开刷新    public static final int STATE_REFRESHING         = 2;//正在刷新    //当前默认状态为下拉刷新    private             int mCurrentState            = STATE_PULL_TO_REFRESH;    private int             mMeasuredHeight;    private float           startY;    private View            headerView;    private ImageView       ivArrow;    private TextView        tvStatus;    private ProgressBar     pbLoading;    private RotateAnimation upAnimation;    private RotateAnimation downAnimation;    private View            footView;    private int             footViewHight;    public RefreshListVeiw(Context context) {        this(context, null);    }    public RefreshListVeiw(Context context, AttributeSet attrs) {        this(context, attrs, -1);    }    public RefreshListVeiw(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initHeaderView(context);        initFootView(context);        initAnimation();    }    private void initHeaderView(Context context) {        headerView = View.inflate(context, R.layout.view_header, null);        ivArrow = (ImageView) headerView.findViewById(R.id.ivArrow);        tvStatus = (TextView) headerView.findViewById(R.id.tvStatus);        pbLoading = (ProgressBar) headerView.findViewById(R.id.pbLoading);        this.addHeaderView(headerView);        //padding值能改变控件的大小        //获取头布局的高度        /**         * View的生命周期和Activity的生命周期         * 并不是同步的,如果Activity的生命周期中         * View还没有测量完毕         */        headerView.measure(0, 0);        mMeasuredHeight = headerView.getMeasuredHeight();        headerView.setPadding(0, -mMeasuredHeight, 0, 0);    }    /**     * 想要在listView向下滑动的时候,将头布局     * 一点一点显示出来,这个时候就要响应ListView     * 的滑动事件     */    @Override    public boolean onTouchEvent(MotionEvent ev) {        int action = ev.getAction();        switch (action) {            case MotionEvent.ACTION_DOWN:                startY = ev.getY();                break;            case MotionEvent.ACTION_MOVE:                float moveY = ev.getY();                float dy = moveY - startY;                /**                 * 此时ListView第一个可见条目就是                 * 头布局,头布局此时虽然不可见,                 * 但是相当于一条线,依然是ListView                 * 的第一个可见条目                 */                int firstVisiblePosition = getFirstVisiblePosition();                //如果第一个可见条目是头布局,并且,是向下滑动的时候                if (firstVisiblePosition == 0 && dy > 0) {                    //如果当前状态为正在刷新,则不需要再改变布局的高度了                    if (mCurrentState == STATE_REFRESHING) {                        break;                    }                    //慢慢显示出来                    int paddingTop = (int) (dy - mMeasuredHeight);                    headerView.setPadding(0, paddingTop, 0, 0);                    if (paddingTop < 0) { //下拉刷新状态                        mCurrentState = STATE_PULL_TO_REFRESH;                        refreshState();                    } else { //松开刷新                        mCurrentState = STATE_RELEASE_TO_REFRESH;                        refreshState();                    }                    return true;//代表消费了事件                }                break;            case MotionEvent.ACTION_UP:                if (mCurrentState == STATE_PULL_TO_REFRESH) {                    //隐藏头布局                    headerView.setPadding(0, -mMeasuredHeight, 0, 0);                } else if (mCurrentState == STATE_RELEASE_TO_REFRESH) {                    //更新状态                    mCurrentState = STATE_REFRESHING;                    refreshState();                    //让头部局完全显示                    headerView.setPadding(0, 0, 0, 0);                    //加载数据                    notifyOnRefresh();                }                break;        }        return super.onTouchEvent(ev);    }    private void refreshState() {        switch (mCurrentState) {            case STATE_PULL_TO_REFRESH:                //设置为GONE会影响布局显示的情况                pbLoading.setVisibility(INVISIBLE);                ivArrow.setVisibility(VISIBLE);                tvStatus.setText("下拉刷新");                ivArrow.setAnimation(upAnimation);                break;            case STATE_RELEASE_TO_REFRESH:                pbLoading.setVisibility(INVISIBLE);                ivArrow.setVisibility(VISIBLE);                ivArrow.setAnimation(downAnimation);                tvStatus.setText("松开刷新");                break;            case STATE_REFRESHING:                pbLoading.setVisibility(VISIBLE);                ivArrow.setVisibility(INVISIBLE);                //需要把ivArrow的动画移除,才能把ivArrow隐藏起来                ivArrow.clearAnimation();                tvStatus.setText("正在刷新");                break;        }    }    private void initAnimation() {        upAnimation = new RotateAnimation(0, -180,                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,                0.5f);        upAnimation.setDuration(200);        upAnimation.setFillAfter(true);        downAnimation = new RotateAnimation(-180, 0,                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,                0.5f);        downAnimation.setDuration(200);        downAnimation.setFillAfter(true);    }    private boolean isLoadingMore = false;    //当滚动状态发生改变的时候,发生的回调    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        if (scrollState == SCROLL_STATE_IDLE && !isLoadingMore) {            int lastVisiblePosition = getLastVisiblePosition();            if (lastVisiblePosition == getCount() - 1) {                // getCount()-1是那一条脚布局的线                //显示脚布局                footView.setPadding(0, 0, 0, 0);                //需要让脚布局自己显示出来                setSelection(getCount() - 1);                isLoadingMore = true;                //加载下一页数据                notifyOnLoadMore();            }        }    }    //这个滚动过程都会进行的回调    @Override    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {    }    //定义回调接口    public interface onRefreshListener {        void onRefresh();        void onLoadMore();    }    //保存接口引用    private onRefreshListener mListener;    public void setOnRefreshListener(onRefreshListener listener) {        this.mListener = listener;    }    private void notifyOnRefresh() {        if (mListener != null) {            mListener.onRefresh();        }    }    private void notifyOnLoadMore() {        if (mListener != null) {            mListener.onLoadMore();        }    }    //数据刷新后需要隐藏headerView,并改变状态    public void onRefreshComplete() {        headerView.setPadding(0, -mMeasuredHeight, 0, 0);        mCurrentState = STATE_PULL_TO_REFRESH;        pbLoading.setVisibility(INVISIBLE);        ivArrow.setVisibility(VISIBLE);        tvStatus.setText("下拉刷新");    }    private void initFootView(Context context) {        footView = View.inflate(context, R.layout.view_footer, null);        footView.measure(0, 0);        footViewHight = footView.getMeasuredHeight();        footView.setPadding(0, -footViewHight, 0, 0);        this.addFooterView(footView);        this.setOnScrollListener(this);    }    public void onLoadMoreComplete() {        isLoadingMore = false;        footView.setPadding(0, -footViewHight, 0, 0);    }}

public class MainActivity extends AppCompatActivity {    private RefreshListVeiw mListView;    private ArrayList<NewsData> mList = new ArrayList<>();    private MainActivity mContent;    private MyAdapter    myAdapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mContent = MainActivity.this;        initData();        mListView = (RefreshListVeiw) findViewById(R.id.listView);        myAdapter = new MyAdapter();        mListView.setAdapter(myAdapter);        mListView.setOnRefreshListener(new RefreshListVeiw.onRefreshListener() {            @Override            public void onRefresh() {                initData();                myAdapter.notifyDataSetChanged();                //加载数据成功后,隐藏布局                mListView.onRefreshComplete();            }            @Override            public void onLoadMore() {                initData();                myAdapter.notifyDataSetChanged();                mListView.onLoadMoreComplete();            }        });    }    private int index = 1;    private void initData() {        for (int i = 0; i < 10; i++) {            NewsData newsData = new NewsData();            newsData.content = "我是第" + index + "item";            index++;            mList.add(newsData);        }    }    class MyAdapter extends BaseAdapter {        @Override        public int getCount() {            return mList.size();        }        @Override        public Object getItem(int position) {            return mList.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) {                convertView = View.inflate(mContent, R.layout.view_item_listview, null);                holder = new ViewHolder();                holder.tvContent = (TextView) convertView.findViewById(R.id.tvContent);                convertView.setTag(holder);            }            holder = (ViewHolder) convertView.getTag();            holder.tvContent.setText(mList.get(position).content);            return convertView;        }    }    static class ViewHolder {        TextView tvContent;    }}

原创粉丝点击