您的位置:首页 > 其它

自定义ListView_下拉刷新上拉加载更多

2015-07-09 17:54 417 查看
自定义ListView实现下拉刷新和上拉自动加载

效果图:

下拉效果:







上拉效果:



实现原理:通过ListView的addFooter与addHeader方法,将下拉布局与上拉布局添加到ListView中,再通过设置padding属性,隐藏头部和脚部

     监听onTouchEvent事件,根据手势滑动距离,动态更改下拉布局的padding,并动态更改头布局内控件效果

     监听onScrollStateChanged,动态显示隐藏脚布局

设置回调,提供下拉刷新与加载更多的方法

Demo:http://files.cnblogs.com/files/liujingg/PullRefreshDemo.rar

PullListView.java

import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

/**
* 自定义ListView,下拉刷新、上拉自动加载更多
* @author liujing
* @version 1.0
*/
public class PullListView extends ListView implements OnScrollListener {

private final int PULL_DOWN_REFRESH = 0;//下拉状态
private final int RELEASE_REFRESH = 1;//松开状态
private final int REFRESHING = 2;//刷新中状态
private int currentState = PULL_DOWN_REFRESH;
private int mListViewOnScreenY = -1;
private int downY = -1;

private boolean isLoadingMore = false;
private boolean isEnabledPullDownRefresh = false;
private boolean isEnabledLoadMore = false;
private OnPullDownRefresh mOnPullDownRefresh;

//头布局、脚布局及高度
private View mFootView;
private LinearLayout mHeaderView;
private int mFooterViewHeight;
private int mPullDownHeaderViewHeight;

//mHeaderView中组件及动画
private View mCustomHeaderView;//用户自定义头布局
private View mPullDownHeader;//下拉刷新头布局
private RotateAnimation upAnimation,downAnimation;
private ImageView ivArrow;
private ProgressBar mProgressBar;
private TextView tv_statue,tv_time;

public PullListView(Context context) {
this(context, null);
}

public PullListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public PullListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initPullDownHeaderView();
initLoadMoreFooterView();
}

private void initLoadMoreFooterView() {
//加载更多的布局文件
mFootView = View.inflate(getContext(), R.layout.pull_listview_footer,
null);
mFootView.measure(0, 0);//测量
mFooterViewHeight = mFootView.getMeasuredHeight();
//隐藏脚布局
mFootView.setPadding(0,-mFooterViewHeight,0,0);
addFooterView(mFootView);
setOnScrollListener(this);
}

private void initPullDownHeaderView() {
//下拉刷新的布局文件
mHeaderView = (LinearLayout) View.inflate(getContext(),
R.layout.pull_listview_header, null);
mPullDownHeader = mHeaderView
.findViewById(R.id.ll_refresh_pull_down_header);
ivArrow = (ImageView) mHeaderView
.findViewById(R.id.iv_refresh_header_arrow);
mProgressBar = (ProgressBar) mHeaderView
.findViewById(R.id.pb_refresh_header);
tv_statue = (TextView) mHeaderView
.findViewById(R.id.tv_refresh_header_status);
tv_time = (TextView) mHeaderView
.findViewById(R.id.tv_refresh_header_time);
mPullDownHeader.measure(0, 0);//测量
mPullDownHeaderViewHeight = mPullDownHeader.getMeasuredHeight();
//隐藏头布局
mPullDownHeader.setPadding(0, -mPullDownHeaderViewHeight, 0, 0);
addHeaderView(mHeaderView);
initAnimation();
}

/**
* 添加额外的头布局,比如轮播图
* @param v 自定义头布局
*/
public void addListViewCustomHeaderView(View v) {
mCustomHeaderView = v;
mHeaderView.addView(mCustomHeaderView);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if (downY == -1)
downY = (int) ev.getY();
//是否启用下拉刷新
if (!isEnabledPullDownRefresh)
break;
if (currentState == REFRESHING)
break;
//解决用户添加header与下拉刷新header的冲突
if (mCustomHeaderView != null) {
int[] location = new int[2];
if (mListViewOnScreenY == -1) {
this.getLocationOnScreen(location);
mListViewOnScreenY = location[1];
}
mCustomHeaderView.getLocationOnScreen(location);
if (location[1] < mListViewOnScreenY) {
break;
}
}

int moveY = (int) ev.getY();
int diffY = (moveY - downY)/2;
if (diffY > 0 && getFirstVisiblePosition() == 0) {
int paddingTop = -mPullDownHeaderViewHeight + diffY;
if (paddingTop < 0 && currentState != PULL_DOWN_REFRESH) {
//当前没有完全显示且当前状态为松开刷新,进入下拉刷新
currentState = PULL_DOWN_REFRESH;
refreshPullDownState();
} else if (paddingTop > 0 && currentState != RELEASE_REFRESH) {
//当前完全显示且当前状态为下拉刷新,进入松开刷新
currentState = RELEASE_REFRESH;
refreshPullDownState();
}
mPullDownHeader.setPadding(0, paddingTop, 0, 0);
return true;
}else if(diffY < 0 && getLastVisiblePosition() == getCount()-1){
//脚布局可向上滑动
mFootView.setPadding(0,0,0,0);
}
break;
case MotionEvent.ACTION_UP:
downY = -1;
if (currentState == PULL_DOWN_REFRESH) {
//隐藏header
mPullDownHeader.setPadding(0, -mPullDownHeaderViewHeight, 0, 0);
} else if (currentState == RELEASE_REFRESH) {
currentState = REFRESHING;
refreshPullDownState();
mPullDownHeader.setPadding(0, 0, 0, 0);
//回调刷新方法
if (mOnPullDownRefresh != null) {
mOnPullDownRefresh.onPullDownRefresh();
}
}
break;
}
return super.onTouchEvent(ev);
}

/**
* 隐藏头布局或脚布局并重置控件
*/
public void OnRefreshDataFinish() {
if (isLoadingMore) {
isLoadingMore = false;
mFootView.setPadding(0,-mFooterViewHeight,0,0);
} else {
ivArrow.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
tv_statue.setText("下拉刷新");
tv_time.setText("最后刷新时间:" + getCurrentTime());
mPullDownHeader.setPadding(0, -mPullDownHeaderViewHeight, 0, 0);
currentState = PULL_DOWN_REFRESH;

}
}

private String getCurrentTime() {
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
return format.format(new Date());
}

private void refreshPullDownState() {
switch (currentState) {
case PULL_DOWN_REFRESH:
ivArrow.startAnimation(downAnimation);
tv_statue.setText("下拉刷新");
break;
case RELEASE_REFRESH:
ivArrow.startAnimation(upAnimation);
tv_statue.setText("松开刷新");
break;
case REFRESHING:
ivArrow.clearAnimation();
ivArrow.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
tv_statue.setText("正在刷新");
break;
default:
break;
}
}

/**
* 箭头旋转动画
*/
private void initAnimation() {
upAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
upAnimation.setDuration(200);
upAnimation.setFillAfter(true);

downAnimation = new RotateAnimation(-180, -360,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
downAnimation.setDuration(200);
downAnimation.setFillAfter(true);
}

/**
* 回调方法,用于刷新数据及加载更多
* @param listener
*/
public void setOnPullDownRefresh(OnPullDownRefresh listener) {
this.mOnPullDownRefresh = listener;
}

public interface OnPullDownRefresh {
public void onPullDownRefresh();
public void onLoadingMore();
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (!isEnabledLoadMore) {
return;
}
//listView停止状态或惯性滑动状态
if (scrollState == SCROLL_STATE_IDLE
|| scrollState == SCROLL_STATE_FLING) {
//listView已到达最底部
if ((getLastVisiblePosition() == getCount() - 1) && !isLoadingMore) {
isLoadingMore = true;
//展示脚布局
//mFootView.setPadding(0, 0, 0, 0);
setSelection(getCount());
if (mOnPullDownRefresh != null) {
mOnPullDownRefresh.onLoadingMore();
}
}
}
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {

}

/**
* 是否启用下拉刷新
* @param isEnable
*/
public void setEnabledPullDownRefresh(boolean isEnable) {
isEnabledPullDownRefresh = isEnable;
}

/**
* 是否启用加载更多
* @param isEnable
*/
public void setEnabledLoadMore(boolean isEnable) {
isEnabledLoadMore = isEnable;
}
}


pull_listview_header.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >

<LinearLayout
android:id="@+id/ll_refresh_pull_down_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<FrameLayout
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginBottom="3dp"
android:layout_marginLeft="28dp"
android:layout_marginTop="8dp" >

<ImageView
android:id="@+id/iv_refresh_header_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/common_listview_headview_red_arrow" />

<ProgressBar
android:id="@+id/pb_refresh_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/custom_progressbar"
android:visibility="invisible" />
</FrameLayout>

<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:gravity="center_horizontal"
android:orientation="vertical" >

<TextView
android:id="@+id/tv_refresh_header_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="#ff0000"
android:textSize="16sp"
android:textStyle="bold" >
</TextView>

<TextView
android:id="@+id/tv_refresh_header_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="最后刷新时间:09:23:23"
android:textColor="@android:color/darker_gray"
android:textSize="12sp" >
</TextView>
</LinearLayout>
<TextView
android:layout_width="40dp"
android:layout_marginRight="28dp"
android:layout_height="wrap_content"
/>
</LinearLayout>

</LinearLayout>


pull_listview_footer.xml

<?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="center"
android:orientation="horizontal" >

<ProgressBar
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_margin="2dp"
android:indeterminateDrawable="@drawable/custom_progressbar" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="加载更多..."
android:textColor="#ff0000"
android:textSize="18sp" />

</LinearLayout>


custom_progressbar.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" >

<shape
android:innerRadiusRatio="4"
android:shape="ring"
android:thicknessRatio="10"
android:useLevel="false" >
<gradient
android:centerColor="#ff6666"
android:endColor="#ff0000"
android:startColor="#ffffff"
android:type="sweep" />
</shape>

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