ListView实现下拉刷新

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()函数当中处理,但是注意新开线程~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值