你的位置:首页 > 操作系统

[操作系统]自定义ListView_下拉刷新上拉加载更多


自定义ListView实现下拉刷新和上拉自动加载

效果图:

下拉效果:

 

上拉效果:

 

实现原理:通过ListView的addFooter与addHeader方法,将下拉布局与上拉布局添加到ListView中,再通过设置padding属性,隐藏头部和脚部

     监听onTouchEvent事件,根据手势滑动距离,动态更改下拉布局的padding,并动态更改头布局内控件效果

     监听onScrollStateChanged,动态显示隐藏脚布局

              设置回调,提供下拉刷新与加载更多的方法

PullListView.java

package com.topsec.topseccsoc.view;import java.text.SimpleDateFormat;import java.util.Date;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.animation.Animation;import android.view.animation.RotateAnimation;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.TextView;import com.topsec.topseccsoc.R;/** * 自定义ListView,下拉刷新、上拉自动加载更多 * @author liujing * @version 1.0 */public class PullListView extends ListView implements OnScrollListener {  private final int PULL_DOWN_REFRESH = 0;//下拉状态  private final int RELEASE_REFRESH = 1;//松开状态  private final int REFRESHING = 2;//刷新中状态  private int currentState = PULL_DOWN_REFRESH;  private int mListViewOnScreenY = -1;  private int downY = -1;    private boolean isLoadingMore = false;  private boolean isEnabledPullDownRefresh = false;  private boolean isEnabledLoadMore = false;  private OnPullDownRefresh mOnPullDownRefresh;    //头布局、脚布局及高度  private View mFootView;  private LinearLayout mHeaderView;  private int mFooterViewHeight;  private int mPullDownHeaderViewHeight;    //mHeaderView中组件及动画  private View mCustomHeaderView;//用户自定义头布局  private View mPullDownHeader;//下拉刷新头布局  private RotateAnimation upAnimation,downAnimation;  private ImageView ivArrow;  private ProgressBar mProgressBar;  private TextView tv_statue,tv_time;    public PullListView(Context context) {    this(context, null);  }  public PullListView(Context context, AttributeSet attrs) {    this(context, attrs, 0);  }  public PullListView(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);    initPullDownHeaderView();    initLoadMoreFooterView();  }    private void initLoadMoreFooterView() {    //加载更多的布局文件    mFootView = View.inflate(getContext(), R.layout.pull_listview_footer,        null);    mFootView.measure(0, 0);//测量    mFooterViewHeight = mFootView.getMeasuredHeight();    //隐藏脚布局    mFootView.setPadding(0,-mFooterViewHeight,0,0);    addFooterView(mFootView);    setOnScrollListener(this);  }  private void initPullDownHeaderView() {    //下拉刷新的布局文件    mHeaderView = (LinearLayout) View.inflate(getContext(),        R.layout.pull_listview_header, null);    mPullDownHeader = mHeaderView        .findViewById(R.id.ll_refresh_pull_down_header);    ivArrow = (ImageView) mHeaderView        .findViewById(R.id.iv_refresh_header_arrow);    mProgressBar = (ProgressBar) mHeaderView        .findViewById(R.id.pb_refresh_header);    tv_statue = (TextView) mHeaderView        .findViewById(R.id.tv_refresh_header_status);    tv_time = (TextView) mHeaderView        .findViewById(R.id.tv_refresh_header_time);    mPullDownHeader.measure(0, 0);//测量    mPullDownHeaderViewHeight = mPullDownHeader.getMeasuredHeight();    //隐藏头布局    mPullDownHeader.setPadding(0, -mPullDownHeaderViewHeight, 0, 0);    addHeaderView(mHeaderView);    initAnimation();  }    /**   * 添加额外的头布局,比如轮播图   * @param v 自定义头布局   */  public void addListViewCustomHeaderView(View v) {    mCustomHeaderView = v;    mHeaderView.addView(mCustomHeaderView);  }  @Override  public boolean onTouchEvent(MotionEvent ev) {    switch (ev.getAction()) {    case MotionEvent.ACTION_DOWN:      downY = (int) ev.getY();      break;    case MotionEvent.ACTION_MOVE:      if (downY == -1)        downY = (int) ev.getY();      //是否启用下拉刷新      if (!isEnabledPullDownRefresh)        break;      if (currentState == REFRESHING)        break;      //解决用户添加header与下拉刷新header的冲突      if (mCustomHeaderView != null) {        int[] location = new int[2];        if (mListViewOnScreenY == -1) {          this.getLocationOnScreen(location);          mListViewOnScreenY = location[1];        }        mCustomHeaderView.getLocationOnScreen(location);        if (location[1] < mListViewOnScreenY) {          break;        }      }      int moveY = (int) ev.getY();      int diffY = (moveY - downY)/2;      if (diffY > 0 && getFirstVisiblePosition() == 0) {        int paddingTop = -mPullDownHeaderViewHeight + diffY;        if (paddingTop < 0 && currentState != PULL_DOWN_REFRESH) {          //当前没有完全显示且当前状态为松开刷新,进入下拉刷新          currentState = PULL_DOWN_REFRESH;          refreshPullDownState();        } else if (paddingTop > 0 && currentState != RELEASE_REFRESH) {          //当前完全显示且当前状态为下拉刷新,进入松开刷新          currentState = RELEASE_REFRESH;          refreshPullDownState();        }        mPullDownHeader.setPadding(0, paddingTop, 0, 0);        return true;      }else if(diffY < 0 && getLastVisiblePosition() == getCount()-1){        //脚布局可向上滑动        mFootView.setPadding(0,0,0,0);      }      break;    case MotionEvent.ACTION_UP:      downY = -1;      if (currentState == PULL_DOWN_REFRESH) {        //隐藏header        mPullDownHeader.setPadding(0, -mPullDownHeaderViewHeight, 0, 0);      } else if (currentState == RELEASE_REFRESH) {        currentState = REFRESHING;        refreshPullDownState();        mPullDownHeader.setPadding(0, 0, 0, 0);        //回调刷新方法        if (mOnPullDownRefresh != null) {          mOnPullDownRefresh.onPullDownRefresh();        }      }      break;    }    return super.onTouchEvent(ev);  }    /**   * 隐藏头布局或脚布局并重置控件   */  public void OnRefreshDataFinish() {    if (isLoadingMore) {      isLoadingMore = false;      mFootView.setPadding(0,-mFooterViewHeight,0,0);    } else {      ivArrow.setVisibility(View.VISIBLE);      mProgressBar.setVisibility(View.INVISIBLE);      tv_statue.setText("下拉刷新");      tv_time.setText("最后刷新时间:" + getCurrentTime());      mPullDownHeader.setPadding(0, -mPullDownHeaderViewHeight, 0, 0);      currentState = PULL_DOWN_REFRESH;    }  }  private String getCurrentTime() {    SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");    return format.format(new Date());  }  private void refreshPullDownState() {    switch (currentState) {    case PULL_DOWN_REFRESH:      ivArrow.startAnimation(downAnimation);      tv_statue.setText("下拉刷新");      break;    case RELEASE_REFRESH:      ivArrow.startAnimation(upAnimation);      tv_statue.setText("松开刷新");      break;    case REFRESHING:      ivArrow.clearAnimation();      ivArrow.setVisibility(View.INVISIBLE);      mProgressBar.setVisibility(View.VISIBLE);      tv_statue.setText("正在刷新");      break;    default:      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, -360,        Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,        0.5f);    downAnimation.setDuration(200);    downAnimation.setFillAfter(true);  }    /**   * 回调方法,用于刷新数据及加载更多   * @param listener   */  public void setOnPullDownRefresh(OnPullDownRefresh listener) {    this.mOnPullDownRefresh = listener;  }  public interface OnPullDownRefresh {    public void onPullDownRefresh();    public void onLoadingMore();  }  @Override  public void onScrollStateChanged(AbsListView view, int scrollState) {    if (!isEnabledLoadMore) {      return;    }    //listView停止状态或惯性滑动状态    if (scrollState == SCROLL_STATE_IDLE        || scrollState == SCROLL_STATE_FLING) {      //listView已到达最底部      if ((getLastVisiblePosition() == getCount() - 1) && !isLoadingMore) {        isLoadingMore = true;        //展示脚布局        //mFootView.setPadding(0, 0, 0, 0);        setSelection(getCount());        if (mOnPullDownRefresh != null) {          mOnPullDownRefresh.onLoadingMore();        }      }    }  }  @Override  public void onScroll(AbsListView view, int firstVisibleItem,      int visibleItemCount, int totalItemCount) {      }    /**   * 是否启用下拉刷新   * @param isEnable   */  public void setEnabledPullDownRefresh(boolean isEnable) {    isEnabledPullDownRefresh = isEnable;  }    /**   * 是否启用加载更多   * @param isEnable   */  public void setEnabledLoadMore(boolean isEnable) {    isEnabledLoadMore = isEnable;  }}

 

 pull_listview_header.

<??><LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="fill_parent"  android:layout_height="wrap_content"  android:orientation="vertical" >  <LinearLayout    android:id="@+id/ll_refresh_pull_down_header"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal" >    <FrameLayout      android:layout_width="40dp"      android:layout_height="40dp"      android:layout_marginBottom="3dp"      android:layout_marginLeft="28dp"      android:layout_marginTop="8dp" >      <ImageView        android:id="@+id/iv_refresh_header_arrow"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:src="@drawable/common_listview_headview_red_arrow" />      <ProgressBar        android:id="@+id/pb_refresh_header"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:indeterminateDrawable="@drawable/custom_progressbar"        android:visibility="invisible" />    </FrameLayout>    <LinearLayout      android:layout_width="fill_parent"      android:layout_height="wrap_content"      android:layout_gravity="center_vertical"      android:layout_weight="1"      android:gravity="center_horizontal"      android:orientation="vertical" >      <TextView        android:id="@+id/tv_refresh_header_status"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="下拉刷新"        android:textColor="#ff0000"        android:textSize="16sp"        android:textStyle="bold" >      </TextView>      <TextView        android:id="@+id/tv_refresh_header_time"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginTop="5dp"        android:text="最后刷新时间:09:23:23"        android:textColor="@android:color/darker_gray"        android:textSize="12sp" >      </TextView>    </LinearLayout>    <TextView       android:layout_width="40dp"      android:layout_marginRight="28dp"      android:layout_height="wrap_content"      />  </LinearLayout></LinearLayout>

pull_listview_footer.

<??><LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:gravity="center"  android:orientation="horizontal" >  <ProgressBar    android:layout_width="40dp"    android:layout_height="40dp"    android:layout_margin="2dp"    android:indeterminateDrawable="@drawable/custom_progressbar" />  <TextView    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:gravity="center"    android:padding="5dp"    android:text="加载更多..."    android:textColor="#ff0000"    android:textSize="18sp" /></LinearLayout>

custom_progressbar.

<??><rotate ="http://schemas.android.com/apk/res/android"  android:fromDegrees="0"  android:pivotX="50%"  android:pivotY="50%"  android:toDegrees="360" >  <shape    android:innerRadiusRatio="4"    android:shape="ring"    android:thicknessRatio="10"    android:useLevel="false" >    <gradient      android:centerColor="#ff6666"      android:endColor="#ff0000"      android:startColor="#ffffff"      android:type="sweep" />  </shape></rotate>