工程需要使用下拉刷新,但是使用网上流传的各种版本均有或多或少的bug,或者效果不完美的地方。
效果图如下:
主要实现的特殊效果如下:
- 下拉时缩减手指滑动距离,实现越拉越难的效果
- 加载状态时,上推界面遮挡部分头部,头部自动收回
- 加载状态时,界面依然可以下拉,松手自动收回,只显示头部
- 加载完成后,有加载完成的状态,停留1秒之后自动收回
- ListView中数据长度没有充满屏幕时,可以下拉刷新
- ListView中没有数据时,可以下拉刷新
- 所有的下拉,回弹均有动画效果
具体的实现思路跟网上的是一样的,就是给ListView添加HeadView,默认隐藏,通过监听OnTouch、OnScroll事件实现滑动时的各种效果。
只说说在实现时遇到的几个问题是怎么解决的:
- 实现越拉越难的效果
在实现拉动越来越难的效果时,通过监听MotionEvent.ACTION_MOVE事件,取手指滑动距离的1/3,代码如下:
if (currentHeaderState != REFRESH_BACED) {
mHeaderLinearLayout.setPadding(
mHeaderLinearLayout.getPaddingLeft(), -mHeaderHeight
+ (int) ((mMoveY - mDownY) / 3),
mHeaderLinearLayout.getPaddingRight(),
mHeaderLinearLayout.getPaddingBottom());
} else if (currentHeaderState == REFRESH_BACED
&& headVisible == true) {
mHeaderLinearLayout.setPadding(
mHeaderLinearLayout.getPaddingLeft(),
(int) ((mMoveY - mDownY) / 3),
mHeaderLinearLayout.getPaddingRight(),
mHeaderLinearLayout.getPaddingBottom());
} else if (currentHeaderState == REFRESH_BACED
&& headVisible == false) {
mHeaderLinearLayout.setPadding(
mHeaderLinearLayout.getPaddingLeft(), -mHeaderHeight
+ (int) ((mMoveY - mDownY) / 3),
mHeaderLinearLayout.getPaddingRight(),
mHeaderLinearLayout.getPaddingBottom());
}
下拉时一共有三种状态:A. 正常状态、B. 加载状态且头部隐藏、C.加载状态且头部显示。
其中A状态和B状态处理方式一样,直接从手指滑动开始计算,拉开滑动距离1/3的效果
C状态时,滑动时位置减去头部的高度,再开始滑动。
直接通过setPadding来实现滑开的效果,且滑动距离缩减1/3,如果手指不松开,来回滑动的话,会导致距离计算不正确,所以在设置回弹效果的时候,要做处理,不然会导致界面收回之后,List中的部分条目也被遮挡。
- 实现回弹动画
这个因为ListView也是在主界面的线程中,所以可以使用Handler.postDelayed()来实现,每次缩减剩余高度的1/4,5毫秒刷新一次即可。
这里主要实现了两个动画,一个是头部隐藏动画,用于未达到刷新状态,和遮挡部分加载中的头部时的动画
另外一个是头部收回动画,用于下拉高度超出头部高度时,头部的松手回弹动画,代码如下:
Runnable headHideAnimation = new Runnable() {
public void run() {
if (mHeaderLinearLayout.getBottom() > 0) {
int paddingTop = (int) (-mHeaderHeight * 0.25f + mHeaderLinearLayout
.getPaddingTop() * 0.75f) - 1;
if (paddingTop < -mHeaderHeight) {
paddingTop = -mHeaderHeight;
}
mHeaderLinearLayout.setPadding(
mHeaderLinearLayout.getPaddingLeft(), paddingTop,
mHeaderLinearLayout.getPaddingRight(),
mHeaderLinearLayout.getPaddingBottom());
handler.postDelayed(headHideAnimation, 5);
} else {
handler.removeCallbacks(headHideAnimation);
mHeaderLinearLayout.setPadding(
mHeaderLinearLayout.getPaddingLeft(), -mHeaderHeight,
mHeaderLinearLayout.getPaddingRight(),
mHeaderLinearLayout.getPaddingBottom());
setSelection(1);
headVisible = false;
}
}
};
Runnable headBackAnimation = new Runnable() {
public void run() {
if (mHeaderLinearLayout.getPaddingTop() > 1) {
mHeaderLinearLayout.setPadding(
mHeaderLinearLayout.getPaddingLeft(),
(int) (mHeaderLinearLayout.getPaddingTop() * 0.75f),
mHeaderLinearLayout.getPaddingRight(),
mHeaderLinearLayout.getPaddingBottom());
handler.postDelayed(headBackAnimation, 5);
} else {
headVisible = true;
handler.removeCallbacks(headBackAnimation);
}
}
};
- 实现ListView中数据没有充满屏幕时的下拉
当ListView中的数据没有充满屏幕的时候,滑动ListView没有内容的部分,监听不到onScrollStateChanged()事件,只能监听到onTouchEvent()、onScroll()这两个事件,如果不做特殊处理的话,会导致下拉之后状态不改变。
所以在onTouchEvent()中的Move事件中将界面的状态由静止改为滑动,即可解决问题。
Comments