APP中是listview布局的界面一般都会有下拉刷新这个功能,很多三方的框架已经实现了,这儿是一个下拉刷新的基本实现。
主要模块:
1.listview中存在addHeaderView(View v)方法,该方法就是在listview头部添加一个自定义的view。(下拉刷新界面就是写在该内容当中)
2.下拉刷新分为下拉中,刷新中,没有下拉三个过程,处理好各个过程的关系。
3.下拉和刷新过程中的view的动画处理。
下面就是下拉刷新的实现代码:
首先自定义刷新界面的布局代码
refresh_head.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:orientation="horizontal" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
>
<!-- 下拉刷新箭头 -->
<ImageView
android:id="@+id/iv_arr"
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_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/custom_progress"
android:visibility="invisible"/>
</FrameLayout>
<LinearLayout
android:padding="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1"
android:gravity="center"
>
<!-- 刷新的界面的文字 -->
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#f00"
android:textSize="16sp"
android:text="下拉刷新"/>
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/darker_gray"
android:textSize="14sp"
android:layout_marginTop="5dp"
android:text="最后刷新时间:2015-03-10 17:20"/>
</LinearLayout>
</LinearLayout>
自定义RefreshListView类继承listview
package view;
import com.lzz.zhihuibeijing.R;
import android.content.Context;
import android.text.StaticLayout;
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.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* 下拉刷新的listview
* @author lizezheng
*
*/
public class RefreshListView extends ListView {
private static final int STATE_PULL_REFRESH = 0; //下拉刷新
private static final int STATE_RELEASE_REFRESH = 1; //松开刷新
private static final int STATE_REFRESHING = 2; //正在刷新
private int mCurrentState = 1;//当前状态的状态码,默认是松开刷新的
private int starty = -1;//下拉刷新起始位置默认-1
private View mHeaderView;//下拉界面view
private int mHeaderViewHeight;// 下拉界面的高度
private TextView tvTitle;
private TextView tvTime;
private ImageView ivArrow;
private ProgressBar pbProgress;
private RotateAnimation animUp;//箭头上指的动画
private RotateAnimation animDown;//箭头下指的动画
//实现构造函数
public RefreshListView(Context context) {
super(context);
initHeaderView();//调用初始化方法
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
}
public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initHeaderView();
}
/**
* 初始化头布局
*/
private void initHeaderView() {
//将下拉界面的布局加载到view当中
mHeaderView = View.inflate(getContext(), R.layout.refresh_head, null);
//将View设置为listview的头部
this.addHeaderView(mHeaderView);
//获取布局当中的所有控件
tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
ivArrow = (ImageView) mHeaderView.findViewById(R.id.iv_arr);
pbProgress = (ProgressBar) mHeaderView.findViewById(R.id.pb_progress);
//测量布局的长宽高度,并获取下拉刷新界面的高度
mHeaderView.measure(0, 0);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
//将下拉刷新界面放到listview界面上方,因为只有我们手像下拉屏幕才会出现刷新界面
mHeaderView.setPadding(0, - mHeaderViewHeight, 0, 0);//隐藏头布局
//初始化动画效果
initArrowAnim();
}
//监听屏幕滑动状况
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
//触摸屏幕时
case MotionEvent.ACTION_DOWN:
//计算触摸屏幕时手指的Y坐标
starty = (int) ev.getRawY();
break;
//滑动屏幕时
case MotionEvent.ACTION_MOVE:
//正在刷新时,不做处理
if(mCurrentState == STATE_REFRESHING){
break;
}
//如果初始Y坐标没有获取到就重新获取一次
if(starty == -1){
starty = (int) ev.getRawY();
}
//获取当前手指的Y坐标
int endy = (int) ev.getRawY();
//计算出偏移量
int dy = endy - starty;//移动偏移量
//只有下拉并且当前是第一个item,才允许下拉刷新
if(dy > 0 && getFirstVisiblePosition() == 0){
//计算padding,即下拉的高度是否超过下拉刷新界面的高度
int padding = dy - mHeaderViewHeight;
//动态改变下拉刷新界面的出现百分比
mHeaderView.setPadding(0, padding, 0, 0);//设置padding
//如果下拉高度超过界面高度,状态改为松开刷新
if(padding > 0 && mCurrentState != STATE_RELEASE_REFRESH){
mCurrentState = STATE_RELEASE_REFRESH;
//调用函数
refreshState();
//刚开始默认是松开刷新状态,所以这里如果下拉高度不够,更换状态,为上面的IF语句做准备
}else if(padding < 0 && mCurrentState != STATE_PULL_REFRESH){
//改为下拉状态
mCurrentState = STATE_PULL_REFRESH;
refreshState();
}
return true;
}
break;
//手指离开屏幕
case MotionEvent.ACTION_UP:
//设置初始Y坐标
starty = -1;
//如果状态是松开刷新状态(表明下拉高度超过)则开始刷新,并更换状态
if(mCurrentState == STATE_RELEASE_REFRESH){
mCurrentState = STATE_REFRESHING;
//显示下拉刷新界面
mHeaderView.setPadding(0, 0, 0, 0);
refreshState();
//如果是下拉状态,说明下拉高度不够,继续隐藏下拉界面
}else if(mCurrentState == STATE_PULL_REFRESH){
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
}
break;
default:
break;
}
return false;
}
/**
* 刷新下拉控件的布局
* 根据状态码来控制下拉界面的动画
*/
private void refreshState() {
switch (mCurrentState) {
//下拉状态
case STATE_PULL_REFRESH:
tvTitle.setText("下拉刷新");
//箭头设置可见
ivArrow.setVisibility(View.VISIBLE);
//转动圆圈设置可见
pbProgress.setVisibility(View.INVISIBLE);
//箭头执行下拉动画
ivArrow.startAnimation(animDown);
break;
case STATE_RELEASE_REFRESH:
tvTitle.setText("松开刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
ivArrow.startAnimation(animUp);
break;
case STATE_REFRESHING:
tvTitle.setText("正在刷新");
ivArrow.clearAnimation();//必须先清除动画才能隐藏
ivArrow.setVisibility(View.INVISIBLE);
pbProgress.setVisibility(View.VISIBLE);
break;
default:
break;
}
}
/**
* 箭头动画
*/
private void initArrowAnim(){
//箭头 向上的动画
animUp = new RotateAnimation(0, -180,Animation.RELATIVE_TO_SELF,
0.5f,Animation.RELATIVE_TO_SELF,0.5f);
//设置动画时间
animUp.setDuration(200);
//设置动画是否保留最终状态
animUp.setFillAfter(true);
//箭头 向下的动画
animDown = new RotateAnimation(-180, 0,Animation.RELATIVE_TO_SELF,
0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animDown.setDuration(200);
animDown.setFillAfter(true);
}
}
刷新当中并没有做什么事情,只是改变了布局的动画,具体的刷新数据可以自行根据自身情况在refreshState()函数当中处理,但是注意新开线程~