Android下拉刷新和加载更多

11年前
/***************************PFView.java*********************************/      /**   * 2013-9-21 下午11:12:45 Created By niexiaoqiang   */    package com.xiaoqiang.m;    import java.text.SimpleDateFormat;  import java.util.ArrayList;  import java.util.Date;  import java.util.Locale;    import android.content.Context;  import android.database.DataSetObserver;  import android.graphics.Color;  import android.util.AttributeSet;  import android.view.Gravity;  import android.view.LayoutInflater;  import android.view.MotionEvent;  import android.view.View;  import android.view.View.OnTouchListener;  import android.view.animation.LinearInterpolator;  import android.view.animation.RotateAnimation;  import android.widget.Button;  import android.widget.ImageView;  import android.widget.LinearLayout;  import android.widget.ProgressBar;  import android.widget.ScrollView;  import android.widget.TextView;    /**   * 1.下拉刷新及加载更多 2.实例控件后需要对设置FPAdapter和PFListener   * 3.如果没有加载到数据,或者其他错误对FPAdaptersetNoda_tip(String noda_tip, boolean   * isclearallview)信息,在onmore时isclearallview为TRUE,onfresh时候为isclearallview为false   * 4.onePagenum控制一页显示多少数据,向服务器递交分页大小   */  public class PFView extends ScrollView implements OnTouchListener {        /************************** 对外使用这些方法就足够了 **************************************/      /**       * 初始化加载数据调用该方法,触发监听器中的onload方法       */      public void loadData() {          if (null != pfListener) {              clearAllview();              // 初始化的时候显示正在初始化              current_state = constant.refrushState.LOADING;              changeHeaderViewByState(current_state);              pfListener.onLoad();          }      }        /**       * 设置设配器       *       * @param pullRefreshAdapter       */      public void setPFAdapter(PFAdapter pfAdapter) {          this.pfAdapter = pfAdapter;          pfAdapter.registerDataSetObserver(dataSetObserver);      }        /**       * 设置监听器       *       * @param pullRefreshListener       */      public void setPullRefreshListener(PFListener pullRefreshListener) {          this.pfListener = pullRefreshListener;      }        /**       * 监听器       *       * @author niexiaoq       *       */      public interface PFListener {          /**           * 下拉刷新           */          public void onRefresh();            /**           * 加载数据           */          public void onLoad();            /**           * 更多           */          public void onMore();      }        /************************** 对外使用这些方法就足够了 **************************************/        /******************************** 更多 ************************************/      private int onePagenum = 20;        /******************************** 更多 ************************************/        /**       * 清除加载进来的所有view,头部不会被清理       */      private void clearAllview() {          ArrayList<View> currentviews = new ArrayList<View>();          for (int i = 0; i < contentLayout.getChildCount(); i++) {              currentviews.add(contentLayout.getChildAt(i));          }          for (int i = 0; i < currentviews.size(); i++) {              View child = currentviews.get(i);              if (pf_header == child) {                  continue;              }              try {                  contentLayout.removeView(currentviews.get(i));              }              catch (Exception e) {                  throw new RuntimeException(e);              }          }      }        /*********************** 滑动相关 ***************/      private int touch_down_y = 0;      private int touch_move_y = 0;      private int touch_down_distance = 0;      private int touch_down_total_distance = 0;      private int pulldown_speed = 2;      private boolean isBack = false;      private boolean isError_topull = false;      private int current_state = constant.refrushState.LOADING;      private PFListener pfListener = null;      private PFAdapter pfAdapter = null;        /*********************** 滑动相关 ***************/      @Override      public boolean onTouch(View v, MotionEvent event) {          this.sv_scrollto(event);          switch (event.getAction()) {              case MotionEvent.ACTION_DOWN:                  touch_down_y = (int) event.getY();                  touch_down_distance = 0;                  break;              case MotionEvent.ACTION_MOVE:                  touch_move_y = (int) event.getY();                  if (touch_down_y == 0) {                      touch_down_y = touch_move_y;                      touch_down_distance = 0;                  }                  touch_down_distance = touch_move_y - touch_down_y;                  touch_down_y = touch_move_y;                  pulldown(touch_down_distance);                  break;              case MotionEvent.ACTION_UP:                  touch_down_y = 0;                  touch_down_distance = 0;                  touch_down_total_distance = 0;                  if (current_state != constant.refrushState.REFRESHING && current_state != constant.refrushState.LOADING && current_state != constant.refrushState.ONMORE) {                      if (current_state == constant.refrushState.DONE) {                      }                      if (current_state == constant.refrushState.PULL_To_REFRESH) {                          if (isError_topull) {                              isError_topull = false;                              current_state = constant.refrushState.ERROR;                          } else {                              current_state = constant.refrushState.DONE;                          }                          changeHeaderViewByState(current_state);                      }                      if (current_state == constant.refrushState.RELEASE_To_REFRESH) {                          current_state = constant.refrushState.REFRESHING;                          changeHeaderViewByState(current_state);                          if (null != pfListener) {                              pfListener.onRefresh();                          }                      }                  }                  break;              default:                  break;          }          return true;      }        /************* 滚动定义 ****************/      private int sv_starty = 0;      private int sv_downy = 0;      private int sv_max_scrolly = 0;        /*************** 滚动定义 **************/      /**       * 滚动       *       * @param y       */      private void sv_scrollto(MotionEvent event) {          sv_max_scrolly = contentLayout.getHeight() - PFView.this.getHeight();          int instatnce_y = 0;          switch (event.getAction()) {              case MotionEvent.ACTION_DOWN:                  sv_starty = (int) event.getY();                  break;              case MotionEvent.ACTION_MOVE:                  sv_downy = (int) event.getY();                  instatnce_y = sv_downy - sv_starty;                  sv_starty = sv_downy;                  break;              case MotionEvent.ACTION_UP:                  sv_downy = (int) event.getY();                  break;              default:                  break;          }          int current_y = getScrollY();          // 只能向上          if (current_y <= 0) {              if (instatnce_y > 0) {                  return;              } else {                  this.scrollTo(0, current_y - instatnce_y);              }          } else if (current_y >= sv_max_scrolly) {              if (instatnce_y < 0) {                  return;              } else {                  this.scrollTo(0, current_y - instatnce_y);              }          } else {              this.scrollTo(0, current_y - instatnce_y);          }      }        /**       * 下拉       *       * @param distance       */      private void pulldown(int distance) {          if (current_state == constant.refrushState.REFRESHING || current_state == constant.refrushState.LOADING || current_state == constant.refrushState.ONMORE) {              return;          }          // PULL_To_REFRESH状态下          if (current_state == constant.refrushState.PULL_To_REFRESH) {              // 下拉到可以进入RELEASE_TO_REFRESH的状态              if (touch_down_total_distance >= HeaderViewHeight) {                  current_state = constant.refrushState.RELEASE_To_REFRESH;                  isBack = true;                  changeHeaderViewByState(current_state);              }              // 上推到顶了              else if (touch_down_total_distance <= 0) {                  current_state = constant.refrushState.DONE;                  changeHeaderViewByState(current_state);              }          }          // RELEASE_To_REFRESH状态下          if (current_state == constant.refrushState.RELEASE_To_REFRESH) {              if (touch_down_total_distance < HeaderViewHeight && touch_down_total_distance > 0) {                  current_state = constant.refrushState.PULL_To_REFRESH;                  changeHeaderViewByState(current_state);              }              // 一下子推到顶了              else if (touch_down_total_distance <= 0) {                  current_state = constant.refrushState.DONE;                  changeHeaderViewByState(current_state);              }          }          // done状态下          if (current_state == constant.refrushState.DONE || current_state == constant.refrushState.ERROR) {              if (current_state == constant.refrushState.ERROR) {                  isError_topull = true;                  touch_down_total_distance = HeaderViewHeight;              }              if (distance > 0) {                  current_state = constant.refrushState.PULL_To_REFRESH;                  changeHeaderViewByState(current_state);              }          }          // 累加总长度          touch_down_total_distance += distance / pulldown_speed;          // 更新headView的size          if (current_state == constant.refrushState.PULL_To_REFRESH) {              pf_header.setPadding(0, -1 * HeaderViewHeight + touch_down_total_distance, 0, 0);            }          // 更新headView的paddingTop          if (current_state == constant.refrushState.RELEASE_To_REFRESH) {              pf_header.setPadding(0, touch_down_total_distance - HeaderViewHeight, 0, 0);          }      }        /**       * 刷新完成,或初始化加载完成时,调用       */      private void onRefresh_LoadingComplete(boolean isscrolltotop) {          current_state = constant.refrushState.DONE;          Date date = new Date();          pf_header_refreshtime.setText("最近更新:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(date));          changeHeaderViewByState(current_state);          this.invalidate();          if (isscrolltotop) {              scrollTo(0, 0);          }      }        /**       * 刷新完成,但加载失败,可能是网络或者其他错误,予以提示,数据从适配器中来       */      private void onRefresh_Error(String errortip) {          this.errortip = errortip;          current_state = constant.refrushState.ERROR;          Date date = new Date();          pf_header_refreshtime.setText("最近更新:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(date));          changeHeaderViewByState(current_state);          this.invalidate();          scrollTo(0, 0);      }        /************** 构造函数 及其他方法 ***************/      /******************* 关于头部文件 ********************/      private LinearLayout contentLayout = null;      /**       * 头部       */      private LinearLayout pf_header = null;      /**       * 头部下拉记载刷新箭头       */      private ImageView pf_header_ico_view = null;      /**       * 头部下拉刷新进度条       */      private ProgressBar pf_header_progressbar = null;        /**       * 头部显示更新时间       */      private TextView pf_header_refreshtime = null;      /**       * 头部提示文字       */      private TextView pf_header_pullnote = null;        private int HeaderViewHeight = 150;        /*** 旋转动画 **********/      private RotateAnimation animation;        private RotateAnimation reverseAnimation;        private String errortip = "";        /**       * 更多按钮       */      private Button morebutton;        /******************* 关于头部文件 ********************/        public PFView(Context context, AttributeSet attrs) {          super(context, attrs);          this.init(context);      }        public PFView(Context context) {          super(context);          this.init(context);      }        public PFView(Context context, AttributeSet attrs, int defStyle) {          super(context, attrs, defStyle);          this.init(context);      }        /**       * 初始化       *       * @param context       */      private void init(Context context) {          /****** 内容容器 *********/          contentLayout = new LinearLayout(context);          contentLayout.setOrientation(LinearLayout.VERTICAL);          this.setOnTouchListener(this);          this.addView(contentLayout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));          /****** 内容容器 *********/          /****** 头部初始化 *********/          pf_header = (LinearLayout) GetPartView(context, R.layout.pf_header);          pf_header.setPadding(0, -1 * HeaderViewHeight, 0, 0);          pf_header.invalidate();          contentLayout.addView(pf_header, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));          pf_header_ico_view = (ImageView) pf_header.findViewById(R.id.pf_header_ico_view);          pf_header_progressbar = (ProgressBar) pf_header.findViewById(R.id.pf_header_progressbar);          pf_header_pullnote = (TextView) pf_header.findViewById(R.id.pf_header_pullnote);          pf_header_refreshtime = (TextView) pf_header.findViewById(R.id.pf_header_refreshtime);          /****** 头部初始化 *********/          /************* 动画初始化 ***************/          animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);          animation.setInterpolator(new LinearInterpolator());          animation.setDuration(250);          animation.setFillAfter(true);          reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);          reverseAnimation.setInterpolator(new LinearInterpolator());          reverseAnimation.setDuration(200);          reverseAnimation.setFillAfter(true);          /************* 动画初始化 ***************/          morebutton = new Button(context);          morebutton.setText("更多...");          morebutton.setTextColor(Color.BLACK);          morebutton.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));          morebutton.setGravity(Gravity.CENTER);          morebutton.setOnClickListener(new OnClickListener() {                @Override              public void onClick(View v) {                  if (null != pfListener) {                      if (current_state == constant.refrushState.DONE) {                          current_state = constant.refrushState.ONMORE;                          pfListener.onMore();                      }                  }              }          });      }        @Override      public boolean onInterceptTouchEvent(MotionEvent ev) {          this.onTouch(this, ev);          return false;      }        /**       * 获取部分UI       *       * @param context       * @param resourceId       * @return       */      private View GetPartView(Context context, int resourceId) {          LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);          return inflater.inflate(resourceId, null);      }        /************** 构造函数 及其他方法 ****************/        /**       * 当状态改变时候,调用该方法,以更新界面       */      private void changeHeaderViewByState(int state) {          switch (state) {              case constant.refrushState.RELEASE_To_REFRESH:                  pf_header_ico_view.setVisibility(View.VISIBLE);                  pf_header_progressbar.setVisibility(View.GONE);                  pf_header_pullnote.setVisibility(View.VISIBLE);                  pf_header_refreshtime.setVisibility(View.VISIBLE);                  pf_header_ico_view.clearAnimation();                  pf_header_ico_view.startAnimation(animation);                  pf_header_pullnote.setText("松开刷新");                  break;              case constant.refrushState.PULL_To_REFRESH:                  pf_header_progressbar.setVisibility(View.GONE);                  pf_header_pullnote.setVisibility(View.VISIBLE);                  pf_header_refreshtime.setVisibility(View.VISIBLE);                  pf_header_ico_view.clearAnimation();                  pf_header_ico_view.setVisibility(View.VISIBLE);                  // 是由RELEASE_To_REFRESH状态转变来的                  if (isBack) {                      isBack = false;                      pf_header_ico_view.clearAnimation();                      pf_header_ico_view.startAnimation(reverseAnimation);                      pf_header_pullnote.setText("下拉刷新");                  } else {                      pf_header_pullnote.setText("下拉刷新");                  }                  break;              case constant.refrushState.REFRESHING:                  pf_header.setPadding(0, 0, 0, 0);                  pf_header_progressbar.setVisibility(View.VISIBLE);                  pf_header_ico_view.clearAnimation();                  pf_header_ico_view.setVisibility(View.GONE);                  pf_header_pullnote.setText("正在刷新...");                  pf_header_refreshtime.setVisibility(View.VISIBLE);                  morebutton.setText("更多...");                  break;              case constant.refrushState.LOADING:                  pf_header.setPadding(0, 0, 0, 0);                  pf_header_progressbar.setVisibility(View.VISIBLE);                  pf_header_ico_view.clearAnimation();                  pf_header_ico_view.setVisibility(View.GONE);                  pf_header_pullnote.setText("正在初始化...");                  pf_header_refreshtime.setVisibility(View.GONE);                  morebutton.setText("更多...");                  break;              case constant.refrushState.DONE:                  pf_header.setPadding(0, -1 * HeaderViewHeight, 0, 0);                  pf_header_progressbar.setVisibility(View.GONE);                  pf_header_ico_view.clearAnimation();                  pf_header_ico_view.setImageResource(R.drawable.pf_header_down_ico);                  pf_header_pullnote.setText("下拉刷新");                  pf_header_refreshtime.setVisibility(View.VISIBLE);                  break;              case constant.refrushState.ERROR:                  pf_header.setPadding(0, 0, 0, 0);                  pf_header_progressbar.setVisibility(View.GONE);                  pf_header_ico_view.clearAnimation();                  pf_header_ico_view.setVisibility(View.GONE);                  pf_header_pullnote.setText(errortip);                  pf_header_refreshtime.setVisibility(View.VISIBLE);                  morebutton.setText("更多...");                  break;          }      }        /**       * 常量       *       * @author niexiaoq       */      public static class constant {            /**           * 状态           *           * @author niexiaoq           */          public static class refrushState {              public final static int ERROR = -1;                public final static int RELEASE_To_REFRESH = 0;                public final static int PULL_To_REFRESH = 1;                public final static int REFRESHING = 2;                public final static int DONE = 3;                public final static int LOADING = 4;                public final static int ONMORE = 5;          }            /**           * 数据行的布局参数           */          public final static LinearLayout.LayoutParams dataViewParas = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);      }        /**       * 调用pullRefreshAdapter。notifyDataSetChanged() 通知发生更改; dataSetObserver开始动作,       */      private DataSetObserver dataSetObserver = new DataSetObserver() {          @Override          public void onChanged() {              super.onChanged();              if (current_state == constant.refrushState.ONMORE) {                  if (pfAdapter.isSucess()) {                      // 清除最后一个控件                      contentLayout.removeViewAt(contentLayout.getChildCount() - 1);                      // 追加 ps:移除更多按钮和头部后,就是在加载更多之前的的数量                      int current_total = contentLayout.getChildCount() - 1;                      ArrayList<? extends View> list = pfAdapter.getAllview();                      // list需要大于当前的数量,加载更多才成功了,否则失败,或者没有更多数据,同样可以获取TIP信息                      if (list.size() > current_total) {                          for (int i = current_total; i < list.size(); i++) {                              contentLayout.addView(list.get(i), constant.dataViewParas);                          }                      }                      // 不添加更多按钮                      if (pfAdapter.isMoredata()) {                          morebutton.setText("更多...");                          contentLayout.addView(morebutton, constant.dataViewParas);                      }                  } else {                      morebutton.setText(pfAdapter.getErrortip());                      contentLayout.addView(morebutton, constant.dataViewParas);                  }                  onRefresh_LoadingComplete(false);              } else {                  if (pfAdapter.isSucess()) {                      clearAllview();                      ArrayList<? extends View> list = pfAdapter.getAllview();                      if (list.size() > 0) {                          for (View view : list) {                              contentLayout.addView(view, constant.dataViewParas);                          }                          if (list.size() >= onePagenum && pfAdapter.isMoredata()) {                              // 添加跟过按钮                              contentLayout.addView(morebutton, constant.dataViewParas);                          }                          onRefresh_LoadingComplete(true);                      } else {                          onRefresh_Error(pfAdapter.getErrortip());                      }                  } else {                      onRefresh_Error(pfAdapter.getErrortip());                  }              }          }      };    }    /**********************PFAdapter.java****************/    /**   * 2013-8-2 上午9:36:42 Created By niexiaoqiang   */    package com.xiaoqiang.m;    import java.util.ArrayList;    import android.content.Context;  import android.view.View;  import android.view.ViewGroup;  import android.widget.BaseAdapter;    /**   * TODO Add Class Description   */  public class PFAdapter extends BaseAdapter {      private ArrayList<? extends View> allView;      private boolean sucess = false;      private boolean moredata = true;      private String errortip = "";        public PFAdapter(Context context, ArrayList<? extends View> allView) {          this.allView = allView;      }        @Override      public int getCount() {          return allView.size();      }        @Override      public Object getItem(int postion) {          return allView.get(postion);      }        @Override      public long getItemId(int postion) {          return 0;      }        @Override      public View getView(int postion, View arg1, ViewGroup arg2) {          return allView.get(postion);      }        public ArrayList<? extends View> getAllview() {          return allView;      }        public void notifyDataSetChanged(boolean sucess, boolean moredata, String errortip) {          this.sucess = sucess;          this.moredata = moredata;          this.errortip = errortip;          super.notifyDataSetChanged();      }        @Override      @Deprecated      public void notifyDataSetChanged() {          super.notifyDataSetChanged();      }        public boolean isSucess() {          return sucess;      }        public boolean isMoredata() {          return moredata;      }        public String getErrortip() {          return errortip;      }    }    /****************************************MainActivity.java****************************/    package com.xiaoqiang.m;    import java.util.ArrayList;    import android.app.Activity;  import android.content.Context;  import android.graphics.Color;  import android.os.Bundle;  import android.os.Handler;  import android.os.Message;  import android.view.Gravity;  import android.view.View;  import android.widget.Button;  import android.widget.LinearLayout;    import com.xiaoqiang.m.PFView.PFListener;    public class MainActivity extends Activity {        private PFView pfView = null;      private PFAdapter pfAdapter = null;      private ArrayList<View> arrayList = null;        private Handler handler = new Handler() {          @Override          public void handleMessage(Message msg) {              super.handleMessage(msg);              Bundle bundle = msg.getData();              pfAdapter.notifyDataSetChanged(bundle.getBoolean("success"), bundle.getBoolean("moredate"), bundle.getString("errortip"));          }      };        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          pfView = (PFView) this.findViewById(R.id.m_pfview);          arrayList = new ArrayList<View>();          pfAdapter = new PFAdapter(this, arrayList);          pfView.setPFAdapter(pfAdapter);          pfView.setPullRefreshListener(new PFListener() {                @Override              public void onRefresh() {                  new Thread(new Runnable() {                      @Override                      public void run() {                          try {                              Thread.sleep(2000);                              arrayList.add(getItemView(MainActivity.this, arrayList.size()));                              Message m = handler.obtainMessage(1);                              Bundle bundle = new Bundle();                              bundle.putBoolean("success", true);                              bundle.putBoolean("moredate", true);                              bundle.putString("errortip", "");                              m.setData(bundle);                              m.sendToTarget();                          }                          catch (Exception e) {                          }                      }                  }).start();              }                @Override              public void onLoad() {                  new Thread(new Runnable() {                        @Override                      public void run() {                          try {                              Thread.sleep(2000);                              for (int i = 0; i < 21; i++) {                                  arrayList.add(getItemView(MainActivity.this, i));                              }                              Message m = handler.obtainMessage(1);                              Bundle bundle = new Bundle();                              bundle.putBoolean("success", true);                              bundle.putBoolean("moredate", true);                              bundle.putString("errortip", "");                              m.setData(bundle);                              m.sendToTarget();                          }                          catch (Exception e) {                          }                      }                  }).start();                }                @Override              public void onMore() {                  new Thread(new Runnable() {                        @Override                      public void run() {                          try {                              Thread.sleep(1000);                              for (int i = 0; i < 10; i++) {                                  arrayList.add(getItemView(MainActivity.this, i));                              }                              Message m = handler.obtainMessage(1);                              Bundle bundle = new Bundle();                              bundle.putBoolean("success", true);                              bundle.putBoolean("moredate", false);                              bundle.putString("errortip", "");                              m.setData(bundle);                              m.sendToTarget();                          }                          catch (Exception e) {                          }                      }                  }).start();                }          });            pfView.loadData();      }        private View getItemView(Context context, int i) {          LinearLayout linearLayout = new LinearLayout(context);          linearLayout.setBackgroundColor(Color.GREEN);          linearLayout.setGravity(Gravity.CENTER);          Button b = new Button(context);          b.setText("测试按钮" + i);          linearLayout.addView(b);          return linearLayout;      }  }