ListView下拉刷新

ListView下拉刷新是在开发过程中经常用到的一个功能,整理如下,如果初学者有需要可以作为参考。
下拉刷新头部布局如下:
   <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/drop_drown_list_header_padding_bottom"
android:paddingTop="@dimen/drop_drown_list_header_padding_top">

<!--进度条  -->
<ProgressBar 
    android:id="@+id/drop_drown_list_header_progress_bar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    style="@style/drop_drown_list_header_progress_bar_style"
    android:indeterminate="true"
    android:layout_toLeftOf="@+id/drop_drown_list_header_default_text_layout"
    android:visibility="gone"/>

<!--翻转图片  -->
<ImageView
    android:id="@+id/drop_drown_list_header_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/image_content"
    android:src="@drawable/drop_down_list_arrow"
    android:layout_toLeftOf="@+id/drop_drown_list_header_default_text_layout"
    android:visibility="gone"/>

<!--文字提示  -->
<RelativeLayout 
    android:id="@+id/drop_drown_list_header_default_text_layout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginLeft="10dp"
    android:gravity="center">

    <TextView 
        android:id="@+id/drop_drown_list_header_default_text"
        style="@style/drop_drown_list_header_font_style"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:gravity="center"/>


    <TextView 
        android:id="@+id/drop_down_list_header_second_text"
        style="@style/drop_drown_list_header_font_style"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/drop_drown_list_header_default_text"
        android:gravity="center"
        android:visibility="gone"/>

</RelativeLayout>

在布局中添加了一个ImageView用于显示下拉的箭头,一个ProgressBar正在加载时候的等待状态,两个TextView用于状态提示和显示时间
接下来是在listView中添加header布局,并在onTouchEvent和滚动事件中改变header中个组件的状态和样式:
public class DropDrownListView extends ListView implements OnScrollListener {

private boolean isDropDrownStyle = true;

private boolean hasReachedTop = false;
//头部不同状态的提示文字
private String headerDefaultText;
private String headerPullText;
private String headerReleaseText;
private String headerLoadingText;

private Context context;
private int currentScrollState;//listView的滚动状态
private int currentHeaderStatus;//头部布局的状态有四种

private RelativeLayout headerLayout;
private ImageView headerImage;
private ProgressBar headerProgressBar;
private TextView headerText;
private TextView headerSecondText;
//动画
private RotateAnimation flipAnimation;
private RotateAnimation reverseFlipAnimation;

private OnScrollListener onScrollListener;

private int headerReleaseMinDistance;

private int headerOriginalHeight;
private int headerOriginalTopPadding;
private float actionDownPointY;
private float headerPaaddingTopRate = 1.5f;
//头部布局的四种状态
public static final int HEADER_STATUS_CLICK_TO_LOAD = 1;
public static final int HEADER_STATUS_DROP_DROWN_TO_LAOD = 2;
public static final int HEADER_STATUS_RELEASE_TO_LOAD = 3;
public static final int HEADER_STATUS_LOADING = 4;

public DropDrownListView(Context context) {
    super(context);
    init(context);
}

public DropDrownListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    getAttrs(context, attrs);
    init(context);
}

public DropDrownListView(Context context, AttributeSet attrs,
        int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    getAttrs(context, attrs);
    init(context);
}

/**
 * 初始化布局
 * 
 * @param context
 */
private void init(Context context) {
    this.context = context;
    initDropDownStyle();
    super.setOnScrollListener(this);
}

private void initDropDownStyle() {
    if (headerLayout != null) {
        if (isDropDrownStyle) {
            addHeaderView(headerLayout);
        } else {
            removeHeaderView(headerLayout);
        }
        return;
    }
    if (!isDropDrownStyle) {
        return;
    }

    headerReleaseMinDistance = getResources().getDimensionPixelSize(
            R.dimen.drop_drown_list_header_release_min_distance);
    flipAnimation = new RotateAnimation(0, 180,
            RotateAnimation.RELATIVE_TO_SELF, 0.5f,
            RotateAnimation.RELATIVE_TO_SELF, 0.5f);
    flipAnimation.setInterpolator(new LinearInterpolator());
    flipAnimation.setDuration(250);
    flipAnimation.setFillAfter(true);

    reverseFlipAnimation = new RotateAnimation(-180, 0,
            RotateAnimation.RELATIVE_TO_SELF, 0.5f,
            RotateAnimation.RELATIVE_TO_SELF, 0.5f);
    reverseFlipAnimation.setInterpolator(new LinearInterpolator());
    reverseFlipAnimation.setDuration(250);
    reverseFlipAnimation.setFillAfter(true);

    headerDefaultText = context
            .getString(R.string.drop_drown_list_header_default_text);
    headerPullText = context
            .getString(R.string.drop_drown_list_header_pull_text);
    headerReleaseText = context
            .getString(R.string.drop_drown_list_header_release_text);
    headerLoadingText = context
            .getString(R.string.drop_drown_list_header_loading_text);

    LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    headerLayout = (RelativeLayout) inflater.inflate(
            R.layout.drop_drown_list_header, null);
    headerText = (TextView) headerLayout
            .findViewById(R.id.drop_drown_list_header_default_text);
    headerImage = (ImageView) headerLayout
            .findViewById(R.id.drop_drown_list_header_image);
    headerProgressBar = (ProgressBar) headerLayout
            .findViewById(R.id.drop_drown_list_header_progress_bar);
    headerSecondText = (TextView) headerLayout
            .findViewById(R.id.drop_down_list_header_second_text);
    headerLayout.setClickable(true);
    headerLayout.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            onDropDown();
        }
    });
    headerText.setText(headerDefaultText);
    addHeaderView(headerLayout);

    measureHeaderLayout(headerLayout);
    headerOriginalHeight = headerLayout.getMeasuredHeight();
    headerOriginalTopPadding = headerLayout.getPaddingTop();
    currentHeaderStatus = HEADER_STATUS_CLICK_TO_LOAD;

}

@Override
public boolean onTouchEvent(MotionEvent ev) {

    hasReachedTop = false;
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
        actionDownPointY = ev.getY();
        break;

    case MotionEvent.ACTION_MOVE:
        adjustHeaderPadding(ev);
        break;

    case MotionEvent.ACTION_UP:
        if (!isVerticalFadingEdgeEnabled()) {
            setVerticalScrollBarEnabled(false);
        }

        if (getFirstVisiblePosition() == 0
                && currentHeaderStatus != HEADER_STATUS_LOADING) {
            switch (currentHeaderStatus) {
            case HEADER_STATUS_RELEASE_TO_LOAD:
                onDropDown();
                break;

            case HEADER_STATUS_DROP_DROWN_TO_LAOD:
                setHeaderStatusClickToLoad();
                setSecondPositionVisible();
                break;
            }
        }

        break;
    }

    return super.onTouchEvent(ev);
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
    currentScrollState = scrollState;
    if (currentScrollState == SCROLL_STATE_IDLE) {
        hasReachedTop = false;
    }
    if (onScrollListener != null) {
        onScrollListener.onScrollStateChanged(view, scrollState);
    }

}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {
    if (currentScrollState == SCROLL_STATE_TOUCH_SCROLL
            && currentHeaderStatus != HEADER_STATUS_LOADING) {
        if (firstVisibleItem == 0) {
            headerImage.setVisibility(View.VISIBLE);
            int pointButtom = headerOriginalHeight
                    + headerReleaseMinDistance;
            if (headerLayout.getBottom() >= pointButtom) {
                setHeaderStatusReleaseToLoad();
            } else if (headerLayout.getBottom() < pointButtom) {
                setHeaderStatusDropDownToLoad();
            }
        } else {
            setHeaderStatusClickToLoad();
        }

    } else if (currentHeaderStatus == SCROLL_STATE_FLING
            && firstVisibleItem == 0
            && currentHeaderStatus != HEADER_STATUS_LOADING) {
        setSecondPositionVisible();
        hasReachedTop = true;
    } else if (currentScrollState == SCROLL_STATE_FLING && hasReachedTop) {
        setSecondPositionVisible();
    }
    if (onScrollListener != null) {
        onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
                totalItemCount);
    }
}

public void setSecondPositionVisible() {
    if (getAdapter() != null && getAdapter().getCount() > 0
            && getFirstVisiblePosition() == 0) {
        setSelection(1);
    }
}

private void adjustHeaderPadding(MotionEvent ev) {
    int pointCount = ev.getHistorySize();
    if (isVerticalFadingEdgeEnabled()) {
        setVerticalScrollBarEnabled(false);
    }
    for (int i = 0; i < pointCount; i++) {
        if (currentHeaderStatus == HEADER_STATUS_DROP_DROWN_TO_LAOD
                || currentHeaderStatus == HEADER_STATUS_RELEASE_TO_LOAD) {
            headerLayout
                    .setPadding(
                            headerLayout.getPaddingLeft(),
                            (int) (((ev.getHistoricalY(i) - actionDownPointY) - headerOriginalHeight) / headerPaaddingTopRate),
                            headerLayout.getPaddingRight(),
                            headerLayout.getPaddingBottom());
        }
    }

}

private void onDropDown() {
    if (currentHeaderStatus != HEADER_STATUS_LOADING
            && onDropDownListener != null) {
        onDropDownBegin();
        onDropDownListener.onDropDown();
    }
}

private void onDropDownBegin() {
    setHeaderStatusLoading();
}

/**
 * headerLayout的初始状态
 */
private void setHeaderStatusClickToLoad() {
    if (currentHeaderStatus != HEADER_STATUS_CLICK_TO_LOAD) {
        resetHeaderPadding();
        headerImage.clearAnimation();
        headerImage.setVisibility(View.GONE);
        headerProgressBar.setVisibility(View.GONE);
        headerText.setText(headerDefaultText);
        currentHeaderStatus = HEADER_STATUS_CLICK_TO_LOAD;

    }
}

/**
 * headerLayout的下拉状态
 */
private void setHeaderStatusDropDownToLoad() {
    if (currentHeaderStatus != HEADER_STATUS_DROP_DROWN_TO_LAOD) {
        headerImage.setVisibility(View.VISIBLE);
        if (currentHeaderStatus != HEADER_STATUS_CLICK_TO_LOAD) {
            headerImage.clearAnimation();
            headerImage.startAnimation(reverseFlipAnimation);
        }
        headerProgressBar.setVisibility(View.GONE);
        headerText.setText(headerPullText);
        if (isVerticalFadingEdgeEnabled()) {
            setVerticalScrollBarEnabled(false);
        }

        currentHeaderStatus = HEADER_STATUS_DROP_DROWN_TO_LAOD;
    }
}

private void setHeaderStatusReleaseToLoad() {
    if (currentHeaderStatus != HEADER_STATUS_RELEASE_TO_LOAD) {
        headerImage.setVisibility(View.GONE);
        headerImage.clearAnimation();
        headerImage.startAnimation(flipAnimation);
        headerProgressBar.setVisibility(View.GONE);
        headerText.setText(headerReleaseText);
        currentHeaderStatus = HEADER_STATUS_RELEASE_TO_LOAD;
    }
}

private void setHeaderStatusLoading() {
    if (currentHeaderStatus != HEADER_STATUS_LOADING) {
        resetHeaderPadding();
        headerImage.setVisibility(View.GONE);
        headerImage.clearAnimation();
        headerProgressBar.setVisibility(View.VISIBLE);
        headerText.setText(headerLoadingText);
        currentScrollState = HEADER_STATUS_LOADING;
        setSelection(0);
    }
}

private void resetHeaderPadding() {
    headerLayout.setPadding(headerLayout.getPaddingLeft(),
            headerOriginalTopPadding, headerLayout.getPaddingRight(),
            headerLayout.getPaddingBottom());
}

private void measureHeaderLayout(View child) {
    ViewGroup.LayoutParams p = child.getLayoutParams();
    if (p == null) {
        p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
    }

    int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, p.width);
    int lpHeight = p.height;
    int childHeightSpace;
    if (lpHeight > 0) {
        childHeightSpace = MeasureSpec.makeMeasureSpec(lpHeight,
                MeasureSpec.EXACTLY);
    } else {
        childHeightSpace = MeasureSpec.makeMeasureSpec(0,
                MeasureSpec.UNSPECIFIED);
    }
    child.measure(childWidthSpec, childHeightSpace);
}

private OnDropDownListener onDropDownListener;

public void OnDropDownComplete(CharSequence secondText) {
    setHeaderSecondText(secondText);
    onDropDownComplete();
}

public void setHeaderSecondText(CharSequence secondText) {
    if (secondText == null) {
        headerSecondText.setVisibility(View.GONE);
    } else {
        headerSecondText.setVisibility(View.VISIBLE);
        headerSecondText.setText(secondText);
    }
}

public void onDropDownComplete() {
    setHeaderStatusClickToLoad();
    if (headerLayout.getBottom() > 0) {
        invalidateViews();
        setSecondPositionVisible();
    }
}

public void setOnDropDownListener(OnDropDownListener listener) {
    onDropDownListener = listener;
}

public interface OnDropDownListener {
    public void onDropDown();
}

private void getAttrs(Context context, AttributeSet attrs) {
    TypedArray ta = context.obtainStyledAttributes(attrs,
            R.styleable.drop_down_list_attr);
    isDropDrownStyle = ta.getBoolean(
            R.styleable.drop_down_list_attr_isDropDownStyle, false);
    ta.recycle();
}

/**
 * 使listView的第二个item可见
 */
@Override
public void setAdapter(ListAdapter adapter) {
    // TODO Auto-generated method stub
    super.setAdapter(adapter);
    setSecondPositionVisible();
}

}
下拉刷新中有四种状态分别为初始状态, 下拉状态, 释放刷新状态,刷新状态。在onTouchEvent()中通过getAction()方法获取到当前的按下的状态 在ACTION_DOWN状态获取点击时Y轴的坐标,在ACTION_MOVE 调节header布局的在Y轴的padding,在ACTION_UP状态下 若在释放刷新状态, 就会加载刷新,在下拉状态则返回初始状态。
在onScroll中根据滚动状态来判断刷新状态,当滚动的距离大于设定的距离是变为释放刷新状态,小于设定距离时变为下拉状态

源码如下http://download.csdn.net/detail/coder0408/8858767

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值