android listview下拉刷新
2015-06-02 18:06
447 查看
原来android里面写个下拉刷新时这么难的....
总体思路是要定义两个控件, 一个是ViewGroup控件, 一个是listview控件, 自定义的ViewGroup包裹着listview, 以方便对其进行控制
效果图和比较长的代码...
布局:
MainActivity.java:
总体思路是要定义两个控件, 一个是ViewGroup控件, 一个是listview控件, 自定义的ViewGroup包裹着listview, 以方便对其进行控制
效果图和比较长的代码...
布局:
<com.lin.pulltorefresh.PullRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pull_refresh_layout" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <include layout="@layout/pull_refresh_head"/> <com.lin.pulltorefresh.PullRefreshListview android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent"/> <include layout="@layout/pull_refresh_foot"/> </com.lin.pulltorefresh.PullRefreshLayout>
MainActivity.java:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView= (ListView) findViewById(R.id.list_view); listView.setAdapter(new MyAdapter(this.getApplicationContext())); // final PullRefreshLayout pullRefreshLayout= (PullRefreshLayout) findViewById(R.id.pull_refresh_layout); final Handler handler=new Handler(); final Runnable failRunnale=new Runnable() { @Override public void run() { pullRefreshLayout.notifyFail(); } }; final Runnable successRunnale=new Runnable() { @Override public void run() { pullRefreshLayout.notifySuccess(); } }; pullRefreshLayout.setListener(new PullRefreshLayout.PullListener() { @Override public void refresh() { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); handler.post(failRunnale); } handler.post(successRunnale); } }).start(); } @Override public void loadMore() { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); handler.post(failRunnale); } handler.post(successRunnale); } }).start(); } }); } class MyAdapter extends BaseAdapter{ int size=32; LayoutInflater lf; ArrayList<String> datas=new ArrayList<>(size); public MyAdapter(Context context){ for (int i=0;i<size;i++) datas.add("data id: "+i); lf=LayoutInflater.from(context); } @Override public int getCount() { return size; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView==null){ convertView=lf.inflate(R.layout.item_adapter,parent,false); } TextView tv= (TextView) convertView.findViewById(R.id.text); tv.setText(datas.get(position)); return convertView; } } }
PullRefreshListview.java
public class PullRefreshListview extends ListView implements PullWidget{ public PullRefreshListview(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean canPullDown() { if (getCount()==0) { return true; } if (getFirstVisiblePosition()==0&&getChildAt(0).getTop()>=0){ return true; } return false; } @Override public boolean canPullUp() { if (getCount()==0) { return true; } View lastView=getChildAt(getLastVisiblePosition()-getFirstVisiblePosition()); if (getLastVisiblePosition()==getCount()-1&&lastView.getBottom()<=getMeasuredHeight()){ return true; } return false; } }
(最复杂的, 主要是因为有太多情况要判断了)PullRefreshLayout.java
public class PullRefreshLayout extends RelativeLayout { ViewGroup headView,footView; View pullTarget; ProgressBar headProgBar,footProgBar; TextView headText,footText; TextView headTimeText,footTimeText; ImageView headIcon,footIcon; PullListener mListener; //config int pullDonwDist,pullUpDist; int speed; int downY; int headHeight,footHeight; boolean first=true; int state; final static int READY_REFRESHING=0,READY_LOAGMOREING=1, NORMAL=2,REFRESHING=31,LOADING=32,RESET=4,SUCCESS=5, FAIL=6,WAITING=7; Handler mHandler; Handler timeHandler; int duration=300; private int fps=60; //date long preRefreshTime=0,preLoadTime=0; RotateAnimation rotateAnimation1=new RotateAnimation(0,180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); RotateAnimation rotateAnimation2=new RotateAnimation(180,0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); public PullRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); state=NORMAL; rotateAnimation1.setDuration(200); rotateAnimation1.setFillAfter(true); rotateAnimation2.setDuration(200); rotateAnimation2.setFillAfter(true); preRefreshTime=preLoadTime=System.currentTimeMillis(); mHandler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (state==RESET||state==SUCCESS||state==FAIL){ if (pullDonwDist>0){ pullDonwDist=pullDonwDist-speed>0?pullDonwDist-speed:0; }else if (pullUpDist<0){ pullUpDist=pullUpDist+speed<0?pullUpDist+speed:0; } requestLayout(); if (pullDonwDist!=0||pullUpDist!=0){ sendEmptyMessageDelayed(0,duration/fps); }else{ state=NORMAL; } } else if (state==REFRESHING){ if (pullDonwDist>headHeight){ pullDonwDist=pullDonwDist-speed>headHeight?pullDonwDist-speed:headHeight; } requestLayout(); if (pullDonwDist!=headHeight){ sendEmptyMessageDelayed(0,duration/fps); } } else if (state==LOADING){ if (pullUpDist<-footHeight){ pullUpDist=pullUpDist+speed<-footHeight?pullUpDist+speed:-footHeight; } requestLayout(); if (pullUpDist!=-footHeight){ sendEmptyMessageDelayed(0,duration/fps); } } } }; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (first){ first=false; headView= (ViewGroup) getChildAt(0); footView= (ViewGroup) getChildAt(2); //init head headIcon= (ImageView) headView.findViewById(R.id.icon); headProgBar= (ProgressBar) headView.findViewById(R.id.progress_bar); headText= (TextView) headView.findViewById(R.id.text); headTimeText= (TextView) headView.findViewById(R.id.time_text); headHeight=headView.getMeasuredHeight(); //init foot footIcon= (ImageView) footView.findViewById(R.id.icon); footProgBar= (ProgressBar) footView.findViewById(R.id.progress_bar); footText= (TextView) footView.findViewById(R.id.text); footTimeText= (TextView) footView.findViewById(R.id.time_text); footHeight=footView.getMeasuredHeight(); //init target pullTarget=getChildAt(1); // timeHandler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (state==REFRESHING){ preRefreshTime=System.currentTimeMillis(); }else if (state==LOADING){ preLoadTime=System.currentTimeMillis(); } else{ headTimeText.setText("上次刷新时间: "+(System.currentTimeMillis()-preRefreshTime)/1000+"秒"); footTimeText.setText("上次刷新时间: "+(System.currentTimeMillis()-preLoadTime)/1000+"秒"); } sendEmptyMessageDelayed(0,1000); } }; timeHandler.sendEmptyMessage(0); } int dist=pullDonwDist+pullUpDist; headView.layout( 0, -headView.getMeasuredHeight()+dist, headView.getMeasuredWidth(), 0+dist); pullTarget.layout( 0, 0+dist, pullTarget.getMeasuredWidth(), pullTarget.getMeasuredHeight()+dist); footView.layout( 0, pullTarget.getMeasuredHeight()+dist, footView.getMeasuredWidth(), pullTarget.getMeasuredHeight()+footView.getMeasuredHeight()+dist); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (state==LOADING||state==RESET||state==SUCCESS||state==FAIL){ return super.dispatchTouchEvent(ev); } switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: downY= (int) ev.getRawY(); pullDonwDist=pullUpDist=0; break; case MotionEvent.ACTION_MOVE: int moveY= (int) ev.getRawY(); int dist=moveY-downY; if (((PullWidget)pullTarget).canPullDown()&&dist>=0){ pullDonwDist=dist/2; pullUpDist=0; if (pullDonwDist>=headHeight){ if (state!=READY_REFRESHING){ state=READY_REFRESHING; headIcon.startAnimation(rotateAnimation1); headText.setText("松开刷新.."); } }else{ if (state!=NORMAL){ headIcon.startAnimation(rotateAnimation2); headText.setText("下拉刷新"); state=NORMAL; } } }else if (((PullWidget)pullTarget).canPullUp()&&dist<=0){ pullDonwDist=0; pullUpDist=dist/2; if (-pullUpDist>=footHeight){ if (state!=READY_LOAGMOREING){ state=READY_LOAGMOREING; footIcon.startAnimation(rotateAnimation1); footText.setText("松开加载更多.."); } }else{ if (state!=NORMAL){ footIcon.startAnimation(rotateAnimation2); footText.setText("上拉刷新"); state=NORMAL; } } }else{ pullDonwDist=pullUpDist=0; return super.dispatchTouchEvent(ev); } requestLayout(); return true; case MotionEvent.ACTION_UP: if (pullDonwDist>0){ //头部复位到刷新的位置 if (state==READY_REFRESHING){ headIcon.clearAnimation(); headIcon.setVisibility(View.INVISIBLE); headProgBar.setVisibility(View.VISIBLE); headText.setText("正在刷新"); state=REFRESHING; if (mListener!=null) { mListener.refresh(); }else{ notifySuccess(); } } //头部复位到0 else{ state=RESET; } speed=pullDonwDist*1000/fps/duration; }else if (-pullUpDist>0){ //尾部复位到刷新的位置 if (state==READY_LOAGMOREING){ footText.setText("正在刷新"); state=LOADING; footIcon.clearAnimation(); footIcon.setVisibility(View.INVISIBLE); footProgBar.setVisibility(View.VISIBLE); if (mListener!=null) { mListener.loadMore(); }else{ notifySuccess(); } } //尾部复位 else{ state=RESET; } speed=-pullUpDist*1000/fps/duration; } if (speed==0) speed=2; mHandler.sendEmptyMessage(0); break; } return super.dispatchTouchEvent(ev); } public void setListener(PullListener pullListener){ mListener=pullListener; } public void notifySuccess() { notifyState(SUCCESS); } public void notifyFail() { notifyState(FAIL); } private void notifyState(int _state) { state=_state; footProgBar.setVisibility(View.GONE); footIcon.setVisibility(View.VISIBLE); footIcon.startAnimation(rotateAnimation2); headProgBar.setVisibility(View.GONE); headIcon.setVisibility(View.VISIBLE); headIcon.startAnimation(rotateAnimation2); mHandler.sendEmptyMessage(0); } public interface PullListener{ public void refresh(); public void loadMore(); }
相关文章推荐
- Android 二维码 生成和识别(附Demo源码)
- android的OOM问题的归纳与解决
- Android Studio中解决Gradle DSL method not found: 'android()'
- Android进步之路八:异步下载图片和图片缓存
- Cubieboard2-Android-Cubie-Screen 模组调试说明 修正1可以显示了 windows ANSI.txt
- Android里的相对坐标
- android中实现View的振动
- Android 属性动画(Property Animation) 完全解析 (下)
- Android 属性动画(Property Animation) 完全解析 (上)
- Android ArrayList LinkedList Set HashMap的介绍.
- Android设计中的尺寸问题
- Android动画效果translate、scale、alpha、rotate详解
- android 上传文件
- Android大图片裁剪终极解决方案(上:原理分析)
- android:layout_gravity和android:gravity的区别
- Android实现简单的倒计时功能
- 两句话,实现android 4.4以上实现沉浸式状态栏
- 平安科技移动开发二队技术周报(第三期)
- 平安科技移动开发二队技术周报(第四期)
- Android Volley完全解析(四),带你从源码的角度理解Volley