ListView下拉刷新及上拉加载更多
①、定义HeaderView
package com.exi.oa.activity.widget.list; import com.exi.oa.R; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.animation.Animation; import android.view.animation.RotateAnimation; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; public class HeaderView extends LinearLayout{ /*定义HeaderView状态*/ public final static int STATE_NORMAL = 0; public final static int STATE_WILL_RELEASE = 1; public final static int STATE_REFRESHING = 2; private int defaultState = STATE_NORMAL; /*定义HeaderView需要的组件*/ private View headerView = null; private ImageView ivArrow = null; private ProgressBar pBar = null; private TextView refreshTips = null; /*定义滑动动画*/ private RotateAnimation upRa = null; private RotateAnimation downRa = null; private final static int ROTATE_DURATION = 250; public HeaderView(Context context){ this(context,null); } public HeaderView(Context context, AttributeSet attrs){ super(context, attrs); initHeaderView(context); } /*初始化HeaderView*/ private void initHeaderView(Context context){ LinearLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0); headerView = LayoutInflater.from(context).inflate(R.layout.refresh_header, null); addView(headerView,lp); setGravity(Gravity.BOTTOM); ivArrow = (ImageView)findViewById(R.id.ivArrow); pBar = (ProgressBar)findViewById(R.id.pbWaiting); refreshTips = (TextView)findViewById(R.id.refresh_tips); upRa = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); upRa.setDuration(ROTATE_DURATION); upRa.setFillAfter(true); downRa = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); downRa.setDuration(ROTATE_DURATION); downRa.setFillAfter(true); } /*设置HeaderView状态*/ public void setHeaderState(int state){ if(defaultState == state){ return; } ivArrow.clearAnimation(); if(state == STATE_REFRESHING){ pBar.setVisibility(View.VISIBLE); ivArrow.setVisibility(View.GONE); }else{ pBar.setVisibility(View.GONE); ivArrow.setVisibility(View.VISIBLE); } switch (state) { case STATE_NORMAL: ivArrow.startAnimation(downRa); refreshTips.setText(R.string.pull_down_for_refresh); break; case STATE_WILL_RELEASE: ivArrow.startAnimation(upRa); refreshTips.setText(R.string.release_for_refresh); break; case STATE_REFRESHING: refreshTips.setText(R.string.refreshing); break; default: break; } defaultState = state; } public int getCurrentState(){ return defaultState; } public void setHeaderHeight(int height){ if(height <= 0){ height = 0; } LayoutParams lp = (LayoutParams)headerView.getLayoutParams(); lp.height = height; headerView.setLayoutParams(lp); } public int getHeaderHeight(){ return headerView.getHeight(); } }
HeaderView布局代码
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ffffff" android:gravity="bottom"> <RelativeLayout android:id="@+id/header_content" android:layout_width="match_parent" android:layout_height="60dip"> <LinearLayout android:id="@+id/layoutTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/refresh_tips" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="15sp" android:text="@string/pull_down_for_refresh"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="4dip"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" android:text="@string/label_update"/> <TextView android:id="@+id/refresh_last_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" android:text="@string/label_last_time"/> </LinearLayout> </LinearLayout> <ImageView android:id="@+id/ivArrow" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_toLeftOf="@id/layoutTitle" android:layout_centerInParent="true" android:layout_marginRight="30dip" android:contentDescription="@string/image_desc" android:src="@drawable/refresh_arrow_down"/> <ProgressBar android:id="@+id/pbWaiting" android:visibility="gone" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_toLeftOf="@id/layoutTitle" android:layout_centerInParent="true" android:layout_marginRight="30dip" style="?android:attr/progressBarStyleSmall"/> </RelativeLayout> </LinearLayout>
②、定义FooterView
package com.exi.oa.activity.widget.list; import com.exi.oa.R; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.animation.Animation; import android.view.animation.RotateAnimation; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; public class FooterView extends LinearLayout{ /*定义FooterView显示项*/ public final static int FOOTER_OPTIONS_PULL = 0; public final static int FOOTER_OPTIONS_CLICK = 1; private static int defaultOptions = FOOTER_OPTIONS_CLICK; /*定义FooterView状态*/ public final static int STATE_NORMAL = 0; public final static int STATE_WILL_RESEALE = 1; public final static int STATE_LOADING = 2; private static int defaultState = STATE_NORMAL; /*定义FooterView需要的组件*/ private View footerView = null; private ImageView ivArrow = null; private ProgressBar pBar = null; private TextView loaderTips = null; /*定义上下拉动画*/ private RotateAnimation upRa = null; private RotateAnimation downRa = null; private final static int ROTATE_DURATION = 250; public FooterView(Context context) { this(context,null); } public FooterView(Context context,AttributeSet atts){ super(context,atts); initFooterView(context); } /*初始化视图*/ private void initFooterView(Context context){ LinearLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0); footerView = LayoutInflater.from(context).inflate(R.layout.loader_footer, null); this.addView(footerView,lp); ivArrow = (ImageView)footerView.findViewById(R.id.ivLoaderArrow); pBar = (ProgressBar)footerView.findViewById(R.id.pbLoaderWaiting); loaderTips = (TextView)footerView.findViewById(R.id.loader_tips); downRa = new RotateAnimation(0.0f, 180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); downRa.setDuration(ROTATE_DURATION); downRa.setFillAfter(true); upRa = new RotateAnimation(180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); upRa.setDuration(ROTATE_DURATION); upRa.setFillAfter(true); setFooterViewOptions(FOOTER_OPTIONS_CLICK); } /*设置footerView项*/ public void setFooterViewOptions(int options){ defaultOptions = options; switch (defaultOptions) { case FOOTER_OPTIONS_PULL: hide(); break; case FOOTER_OPTIONS_CLICK: show(); break; default: break; } } /*获取footerView的项*/ public int getFooterViewOptions(){ return defaultOptions; } /*设置footerview状态*/ public void setFooterSate(int state){ if(this.defaultState == state){ return; } ivArrow.clearAnimation(); if(state == STATE_LOADING){ pBar.setVisibility(View.VISIBLE); ivArrow.setVisibility(View.GONE); }else{ pBar.setVisibility(View.GONE); ivArrow.setVisibility(View.VISIBLE); } switch (state) { case STATE_NORMAL: ivArrow.startAnimation(upRa); loaderTips.setText(R.string.pull_up_for_more); break; case STATE_WILL_RESEALE: ivArrow.startAnimation(downRa); loaderTips.setText(R.string.release_for_more); break; case STATE_LOADING: loaderTips.setText(R.string.loading); break; default: break; } defaultState = state; } /*获取footerView当前状态*/ public int getCurrentState(){ return defaultState; } /*设置footerView的高度*/ public void setFooterHeight(int height){ if(height <= 0){ height = 0; } LayoutParams lp = (LayoutParams)footerView.getLayoutParams(); lp.height = height; footerView.setLayoutParams(lp); } /*获取footerView的高度*/ public int getFooterHeight(){ return footerView.getHeight(); } /*隐藏*/ public void hide(){ ivArrow.clearAnimation(); ivArrow.setVisibility(View.VISIBLE); loaderTips.setText(R.string.pull_up_for_more); setFooterHeight(0); } /*显示*/ public void show(){ ivArrow.clearAnimation(); ivArrow.setVisibility(View.GONE); loaderTips.setText(R.string.click_for_more); LayoutParams lp = (LayoutParams)footerView.getLayoutParams(); lp.height = LayoutParams.WRAP_CONTENT; footerView.setLayoutParams(lp); } }
FooterView布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="top" android:background="#ffffff" > <RelativeLayout android:id="@+id/footer_content" android:layout_width="match_parent" android:layout_height="60dip" > <TextView android:id="@+id/loader_tips" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="@string/pull_up_for_more" android:textSize="15sp" /> <ImageView android:id="@+id/ivLoaderArrow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginRight="30dip" android:layout_toLeftOf="@id/loader_tips" android:contentDescription="@string/image_desc" android:src="@drawable/refresh_arrow_up" /> <ProgressBar android:id="@+id/pbLoaderWaiting" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginRight="30dip" android:layout_toLeftOf="@id/loader_tips" android:visibility="gone" /> </RelativeLayout> </LinearLayout>
③、定义ListView
package com.exi.oa.activity.widget.list; import com.exi.oa.R; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.animation.DecelerateInterpolator; import android.widget.AbsListView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Scroller; import android.widget.AbsListView.OnScrollListener; public class TaskListView extends ListView implements OnScrollListener{ /*定义HeaderView*/ private HeaderView headerView = null; private RelativeLayout headerContent = null; private int headerHeight = 0; /*定义FooterView*/ private FooterView footerView = null; private RelativeLayout footerContent = null; private int footerHeight = 0; private final static int SCROLL_HEADER = 0; private final static int SCROLL_FOOTER = 1; private int defaultScrollWhich = SCROLL_FOOTER; private Scroller scroller = null; private final static float OFFSET_Y = 0.7F; private float iLastY = 0; private int totalNumber = 0; private OnLoaderListener loaderListener; public TaskListView(Context context) { this(context, null, 0); } public TaskListView(Context context,AttributeSet attrs){ this(context, attrs, 0); } public TaskListView(Context context,AttributeSet attrs,int defStyle){ super(context,attrs,defStyle); initView(context); } private void initView(Context context){ scroller = new Scroller(context, new DecelerateInterpolator()); super.setOnScrollListener(this); initFooterView(context); //initHeaderView(context); } /*重写设置适配器方法*/ @Override public void setAdapter(ListAdapter adapter) { if(getFooterViewsCount() == 0){ addFooterView(footerView); } super.setAdapter(adapter); } /*重写触屏事件的回调方法*/ @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //当屏幕被按下时 iLastY = ev.getY(); break; case MotionEvent.ACTION_MOVE: //当在屏幕中滑动时 float deltaY = ev.getY() - iLastY; iLastY = ev.getY(); /*if(canHeaderPull() && getFirstVisiblePosition() == 0 && (deltaY > 0 || headerView.getHeaderHeight() > 0)){ updateHeaderState(deltaY * OFFSET_Y); }else if(canFooterPull() && getLastVisiblePosition() == totalNumber - 1 && (deltaY < 0 || footerView.getFooterHeight() > 0)){ updateFooterState(-deltaY * OFFSET_Y); }*/ if(canFooterPull() && getLastVisiblePosition() == totalNumber - 1 && (deltaY < 0 || footerView.getFooterHeight() > 0)){ updateFooterState(-deltaY * OFFSET_Y); } break; case MotionEvent.ACTION_UP: //当屏幕被抬起时、也就是手指离开屏幕是 /*if(getFirstVisiblePosition() == 0){ if(headerView.getHeaderHeight() > headerHeight){ headerView.setHeaderState(HeaderView.STATE_REFRESHING); if(footerView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){ footerView.hide(); } } resetHeader(); }else if(getLastVisiblePosition() == totalNumber - 1){ if(footerView.getFooterHeight() > footerHeight){ footerView.setFooterSate(FooterView.STATE_LOADING); } resetFooter(); }*/ if(getLastVisiblePosition() == totalNumber - 1){ if(footerView.getFooterHeight() > footerHeight){ footerView.setFooterSate(FooterView.STATE_LOADING); loader(); } resetFooter(); } break; default: break; } return super.onTouchEvent(ev); } @Override public void computeScroll() { if(scroller.computeScrollOffset()){ /*if(defaultScrollWhich == SCROLL_HEADER){ headerView.setHeaderHeight(scroller.getCurrY()); }else */ if(defaultScrollWhich == SCROLL_FOOTER){ footerView.setFooterHeight(scroller.getCurrY()); } } super.computeScroll(); } /* * 滑动时获取ListView有多少个item * 1. 在init中,需要设置super.setOnScrollListener; * 2. 重载以下两个函数; * 3. 在onScroll中取得totalItemCount即可; * */ @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //滑动时触发该方法 totalNumber = totalItemCount; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { //滑动改变时触发该方法 } public void setOnLoaderListener(OnLoaderListener listener){ this.loaderListener = listener; } public void loader(){ if(this.loaderListener != null){ loaderListener.onLoader(); } } /*========================================================================================*/ private boolean canHeaderPull(){ if(footerView.getCurrentState() == FooterView.STATE_NORMAL){ return true; } return false; } public boolean canFooterPull(){ //if(headerView.getCurrentState() == HeaderView.STATE_NORMAL){ return true; //} //return false; } /*==================================================Footer=================================================*/ /*返回FooterView*/ public FooterView getFooterView(){ return footerView; } /*设置Footer模型*/ public void setFooterMode(int options){ footerView.setFooterViewOptions(options); } /*停止加载*/ public void stopLoad(){ if(footerView.getCurrentState() == FooterView.STATE_LOADING){ footerView.setFooterSate(FooterView.STATE_NORMAL); resetFooter(); } } /*初始化footerView*/ private void initFooterView(Context context){ footerView = new FooterView(context); footerContent = (RelativeLayout)footerView.findViewById(R.id.footer_content); footerContent.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(footerView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK && footerView.getCurrentState() == FooterView.STATE_NORMAL){ footerView.setFooterSate(FooterView.STATE_LOADING); loader(); } } }); footerView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { footerHeight = footerContent.getHeight(); getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); } /*更新FooterView状态*/ private void updateFooterState(float delta){ if(footerView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){ return; } footerView.setFooterHeight((int)(delta+footerView.getFooterHeight())); if(footerView.getCurrentState() != FooterView.STATE_LOADING){ if(footerView.getFooterHeight() > footerHeight){ footerView.setFooterSate(FooterView.STATE_WILL_RESEALE); }else{ footerView.setFooterSate(FooterView.STATE_NORMAL); } } } /*重置Footer*/ private void resetFooter(){ int height = footerView.getFooterHeight(); if(height == 0){ return; } if(footerView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){ return; } int finalHeight = 0; if(height > footerHeight){ finalHeight = footerHeight; }else if(footerView.getCurrentState() == FooterView.STATE_LOADING){ return; } defaultScrollWhich = SCROLL_FOOTER; scroller.startScroll(0, height, finalHeight - height, 250); invalidate(); } /*==========================================Header==========================================================*/ /*返回HeaderView public HeaderView getHeaderView(){ return headerView; } 停止刷新 public void stopRefresh(){ if(headerView.getCurrentState() == HeaderView.STATE_REFRESHING){ headerView.setHeaderState(HeaderView.STATE_NORMAL); resetHeader(); if(footerView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){ footerView.show(); } } } 初始化HeaderView private void initHeaderView(Context context){ headerView = new HeaderView(context); headerContent = (RelativeLayout)headerView.findViewById(R.id.header_content); addHeaderView(headerView); headerView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { headerHeight = headerContent.getHeight(); getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); } 更新Headerview状态 private void updateHeaderState(float delta){ headerView.setHeaderHeight((int)(delta + headerView.getHeaderHeight())); if(headerView.getCurrentState() != HeaderView.STATE_REFRESHING){ if(headerView.getHeaderHeight() > headerHeight){ headerView.setHeaderState(HeaderView.STATE_WILL_RELEASE); }else{ headerView.setHeaderState(HeaderView.STATE_NORMAL); } } setSelection(0); } 重置Header private void resetHeader(){ int height = headerView.getHeaderHeight(); if(height == 0){ return; } int finalHeight = 0; if(height > headerHeight){ * 如果超过HeaderView高度,则回滚到HeaderView高度即可 finalHeight = headerHeight; }else if(headerView.getCurrentState() == HeaderView.STATE_REFRESHING){ * 如果HeaderView未完全显示 * 1. 处于正在刷新中,则不管; * 2. 回滚HeaderView当前可视高度 return; } defaultScrollWhich = SCROLL_HEADER; scroller.startScroll(0, height, 0, finalHeight, 250); invalidate(); } */ private class OnClickLoaderListener implements OnClickListener{ @Override public void onClick(View v) { loader(); } } public interface OnLoaderListener{ public void onLoader(); } }
在ListView中定义OnLoaderListener接口作为加载数据监听器、加载数据只需实现此监听器即可