/***************************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; } }