ListView的下拉刷新逻辑:
一、获取ListView的头布局的高度并通过给头布局setPading方法,将头布局隐藏
二、重写ListView的onTouchEvent方法计算出滑动的偏移量dy
三、通过比较偏移量和头布局的高度,进行UI的修改
ListView上拉加载逻辑:
一、获取ListView的脚布局的高度并通过setPading方法,将头布局隐藏
二、调用ListView的setOnScrollListener方法,重写两个方法
1、onScrollStateChanged
当滑动状态是静止状态,并且最后一个条目是脚布局
的时候,显示脚布局,然后加载下一页数据,并修改UI
一、获取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; } }