您的位置:首页 > 移动开发 > Android开发

为自己记------android中listview下拉刷新和下拉加载的原理及简单实现

2015-07-06 11:50 791 查看
自定义listview,实现下拉刷新功能和上拉加载功能

1.下拉刷新

实现原理:通过onTouchEvent判断手势,来改变listview的header。

header的状态共4种,自己定义为:none, normal, willrefresh, refreshing ,header在四种状态切换时不仅改变内部组件,同时改变自身的大小。

footer类似

实现:

import android.content.Context;

import android.os.Handler;

import android.util.AttributeSet;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.widget.AbsListView;

import android.widget.AbsListView.OnScrollListener;

import android.widget.LinearLayout;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.TextView;

import com.windlu.anywhere.R;

/**

* 自定义的listview,实现上拉刷新和下拉加载

* @author lufeng

*

*/

public class PushAndDownListview extends ListView implements OnScrollListener{

private StateBar headView;//头部view

private StateBar footerView;//脚部view

private int headerContentHeight;//头部view的高度

private int footerContentHeight;//脚部view的高度

private static final int Refresh = 0;//刷新

private static final int Load = 1;//加载

private int Operating=-1;//操作

private PushAndDownListviewRefreshOrLoad mPushAndDownListviewRefreshOrLoad;//加载或刷新的回调接口

public PushAndDownListview(Context context) {

this(context,null);

}

public PushAndDownListview(Context context, AttributeSet attrs) {

super(context, attrs);

init(context);

}

private void init(Context context){

//头部

headView = new StateBar(context);

headView.setStatusStrings(getResources().getString(R.string.pull_to_refresh),

getResources().getString(R.string.release_to_refresh),

getResources().getString(R.string.refreshing));

//测量view的高度

measureView(headView);

headerContentHeight=headView.getMeasuredHeight();

//设置view的toppadding值

headtopPadding(-headerContentHeight);

//添加view

addHeaderView(headView);

//脚部

footerView = new StateBar(context);

footerView.setStatusStrings(getResources().getString(R.string.pull_up_load),

getResources().getString(R.string.release_to_load),

getResources().getString(R.string.loading));

measureView(footerView);

footerContentHeight = footerView.getMeasuredHeight();

footerTopPadding(-footerContentHeight);

addFooterView(footerView);

}

float startY;

boolean isRecordedStartY;//是否已经记录StartY

int firstVisibleItemPosition ;

int LastVisibleItemPosition;

int totalItemCounts;

private boolean isRefreshing;

//主要在该方法中实现下拉刷新效果和上拉加载效果

@Override

public boolean onTouchEvent(MotionEvent ev) {

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

if((firstVisibleItemPosition==0 || LastVisibleItemPosition==totalItemCounts) && Operating == -1&&!isRefreshing){

startY = ev.getY();

isRecordedStartY=true;

return true;

}

break;

case MotionEvent.ACTION_UP:

isRecordedStartY=false;

if((firstVisibleItemPosition==0 || LastVisibleItemPosition==totalItemCounts) && Operating != -1&&!isRefreshing){

if(Operating == Refresh){

if(headView.getStateType()==StateType.willrefresh){

headView.setRefreshStatus(StateType.refreshing);

headtopPadding(0);

doRefreshWork();

}else if(headView.getStateType()==StateType.refreshing){

}else{

RefreshWorkComplete();

//
Operating=-1;

//
headView.setRefreshStatus(StateType.none);

//
headtopPadding(-headerContentHeight);

}

}else if(Operating == Load){

if(footerView.getStateType()==StateType.willrefresh){

footerView.setRefreshStatus(StateType.refreshing);

footerTopPadding(0);

doLoadWork();

}else if(footerView.getStateType()==StateType.refreshing){

}else{

LoadWorkComplete();

//
Operating=-1;

//
footerView.setRefreshStatus(StateType.none);

//
footerTopPadding(-footerContentHeight);

}

}

}

break;

case MotionEvent.ACTION_MOVE:

if((firstVisibleItemPosition==0 || LastVisibleItemPosition==totalItemCounts)&&!isRefreshing){

whenMove(ev);

}

break;

default:

break;

}

return super.onTouchEvent(ev);

}

private void doRefreshWork() {

isRefreshing = true;

if(mPushAndDownListviewRefreshOrLoad!=null){

mPushAndDownListviewRefreshOrLoad.Refresh();

}else{

new Handler().postDelayed(new Runnable() {

public void run() {

RefreshWorkComplete();

}

}, 3000);

}

}

private void doLoadWork() {

isRefreshing = true;

if(mPushAndDownListviewRefreshOrLoad!=null){

mPushAndDownListviewRefreshOrLoad.Load();

}else{

new Handler().postDelayed(new Runnable() {

public void run() {

LoadWorkComplete();

}

}, 3000);

}

}

//设置监听

public void setPushAndDownListviewRefreshOrLoadListener(PushAndDownListviewRefreshOrLoad listener){

this.mPushAndDownListviewRefreshOrLoad = listener;

}

//刷新完成后调用

public void RefreshWorkComplete(){

isRefreshing = false;

Operating=-1;

headView.setRefreshStatus(StateType.none);

headtopPadding(-headerContentHeight);

}

//加载完成后调用

public void LoadWorkComplete(){

isRefreshing = false;

Operating = -1;

footerView.setRefreshStatus(StateType.none);

footerTopPadding(-footerContentHeight);

}

private void whenMove(MotionEvent ev){

if(!isRecordedStartY || headView.getStateType()==StateType.refreshing || footerView.getStateType()==StateType.refreshing){

return;

}

float stempY = ev.getY();

int distanceY = (int)(stempY - startY);

if(distanceY > 0 && firstVisibleItemPosition == 0){

//执行刷新状态

doRefresh(distanceY);

}else if(distanceY < 0 && LastVisibleItemPosition==totalItemCounts){

//执行加载状态

doLoad(distanceY);

}

}

private void doRefresh(int distanceY){

Operating = Refresh;

if(distanceY-headerContentHeight < 0){

headView.setRefreshStatus(StateType.normal);

}else if(distanceY-headerContentHeight >= 0){

headView.setRefreshStatus(StateType.willrefresh);

}

headtopPadding(distanceY-headerContentHeight);

}

private void doLoad(int distanceY){

Operating = Load;

if(-(distanceY+footerContentHeight) < 0){

footerView.setRefreshStatus(StateType.normal);

}else if(-(distanceY+footerContentHeight) >= 0){

footerView.setRefreshStatus(StateType.willrefresh);

}

footerTopPadding(-(distanceY+footerContentHeight));

}

/**

* 测量view的方法

* @param view必须使用线性布局

*/

private void measureView(View clild) {

ViewGroup.LayoutParams p = clild.getLayoutParams();//获取layoutparams

if (p == null) {

p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,

ViewGroup.LayoutParams.WRAP_CONTENT);

}

int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);//宽

int lpHeight = p.height;

int childHeightSpec;

if (lpHeight > 0) {

childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,MeasureSpec.EXACTLY);

} else {

childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);

}

clild.measure(childWidthSpec, childHeightSpec);//measure(0,0)必须使用线性布局,否则报空指针异常,因为线性布局重写了该方法,其他没有从写

}

/**

* 为headview从新设置padding

* @param topPadding

*/

private void headtopPadding(int topPadding) {

headView.setPadding(headView.getPaddingLeft(), topPadding,headView.getPaddingRight(), headView.getPaddingBottom());

headView.invalidate();

}

private void footerTopPadding(int topPadding){

footerView.setPadding(footerView.getPaddingLeft(), topPadding,footerView.getPaddingRight(), footerView.getPaddingBottom());

footerView.invalidate();

}

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

this.firstVisibleItemPosition = firstVisibleItem;

this.LastVisibleItemPosition = firstVisibleItem+visibleItemCount;

this.totalItemCounts=totalItemCount;

}

//状态

enum StateType{

none, normal, willrefresh, refreshing

}

//自定义的状态显示view,用于添加到listview的头部和脚部

class StateBar extends LinearLayout{

//状态

StateType mStateType = StateType.none;

//显示的文字

private String normalString;

private String willrefreshString;

private String refreshingString;

public StateBar(Context context) {

super(context);

init(context);

}

public StateBar(Context context, AttributeSet attrs) {

super(context, attrs);

init(context);

}

//ui控件

ProgressBar progressBar;

TextView tv_state;

TextView tv_updatetime;

private void init(Context context){

LayoutInflater.from(context).inflate(R.layout.view_listviewheadorfoot, this);

progressBar = (ProgressBar) findViewById(R.id.progressBar);

tv_state = (TextView) findViewById(R.id.tv_state);

tv_updatetime = (TextView) findViewById(R.id.tv_updatetime);

//设置状态

setRefreshStatus(mStateType);

}

//设置view的当前状态

public void setRefreshStatus(StateType refreshStatus) {

if (this.mStateType != refreshStatus) {

this.mStateType = refreshStatus;

if(mStateType == StateType.refreshing){

this.progressBar.setVisibility(View.VISIBLE);

}else{

this.progressBar.setVisibility(View.GONE);

}

refreshStatusString();

this.invalidate();

}

}

//刷新状态文字

private void refreshStatusString() {

switch (mStateType) {

case none:

case normal:

tv_state.setText(normalString);

break;

case willrefresh:

tv_state.setText(willrefreshString);

break;

case refreshing:

tv_state.setText(refreshingString);

break;

default:

break;

}

//这里先不做时间设置

tv_updatetime.setText("");

}

public StateType getStateType(){

return mStateType;

}

public void setStatusStrings(String normalString, String willrefreshString, String refreshingString){

this.normalString = normalString;

this.willrefreshString = willrefreshString;

this.refreshingString = refreshingString;

this.refreshStatusString();

}

}

interface PushAndDownListviewRefreshOrLoad{

void Refresh();

void Load();

}

}

有待完善。。。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: