package com.dwtedx.qq.view; import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar; import com.dwtedx.tst.R; public class DropdownListView extends ListView implements OnScrollListener { private static final String TAG = "listview"; private final static int RELEASE_To_REFRESH = ;
private final static int PULL_To_REFRESH = ;
private final static int REFRESHING = ;
private final static int DONE = ;
private final static int LOADING = ; // 实际的padding的距离与界面上偏移距离的比例
private final static int RATIO = ; private LayoutInflater inflater;
private FrameLayout fl;
private LinearLayout headView; // private View line;
private ProgressBar progressBar; // private RotateAnimation animation;
// private RotateAnimation reverseAnimation; // 用于保证startY的值在一个完整的touch事件中只被记录一次
private boolean isRecored; private int headContentWidth;
private int headContentHeight; private int startY;
private int firstItemIndex; private int state; private boolean isBack; private OnRefreshListenerHeader refreshListenerHeader; private boolean isRefreshableHeader; public DropdownListView(Context context) {
super(context);
init(context);
} public DropdownListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
} private void init(Context context) {
setCacheColorHint(context.getResources().getColor(R.color.transparent));
inflater = LayoutInflater.from(context); fl = (FrameLayout)inflater.inflate(R.layout.dropdown_lv_head, null);
headView = (LinearLayout) fl.findViewById(R.id.drop_down_head); progressBar = (ProgressBar) fl.findViewById(R.id.loading);
measureView(headView); headContentHeight = headView.getMeasuredHeight();
headContentWidth = headView.getMeasuredWidth(); headView.setPadding(, - * headContentHeight, , );
headView.invalidate(); Log.v("size", "width:" + headContentWidth + " height:"
+ headContentHeight); addHeaderView(fl, null, false);
// addHeaderView(headView, null, false);
setOnScrollListener(this); state = DONE;
isRefreshableHeader = false;
} public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
int arg3) {
firstItemIndex = firstVisiableItem;
} public void onScrollStateChanged(AbsListView arg0, int scrollState) {
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
// 判断滚动到底部 }
} public boolean onTouchEvent(MotionEvent event) { if (isRefreshableHeader) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (firstItemIndex == && !isRecored) {
isRecored = true;
startY = (int) event.getY();
Log.v(TAG, "在down时候记录当前位置‘");
}
break; case MotionEvent.ACTION_UP: if (state != REFRESHING && state != LOADING) {
if (state == DONE) {
// 什么都不做
}
if (state == PULL_To_REFRESH) {
state = DONE;
changeHeaderViewByState(); Log.v(TAG, "由下拉刷新状态,到done状态");
}
if (state == RELEASE_To_REFRESH) {
state = REFRESHING; changeHeaderViewByState();
// recoverLine();
onRefresh(); Log.v(TAG, "由松开刷新状态,到done状态");
}
} isRecored = false;
isBack = false; break; case MotionEvent.ACTION_MOVE:
int tempY = (int) event.getY();
if (!isRecored && firstItemIndex == ) {
Log.v(TAG, "在move时候记录下位置");
isRecored = true;
startY = tempY;
} if (state != REFRESHING && isRecored && state != LOADING) { // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动 // 可以松手去刷新了
if (state == RELEASE_To_REFRESH) { setSelection(); // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
if (((tempY - startY) / RATIO < headContentHeight)
&& (tempY - startY) > ) {
state = PULL_To_REFRESH;
changeHeaderViewByState(); Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");
}
// 一下子推到顶了
else if (tempY - startY <= ) {
state = DONE;
changeHeaderViewByState(); Log.v(TAG, "由松开刷新状态转变到done状态");
}
// 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
else {
// 不用进行特别的操作,只用更新paddingTop的值就行了
}
}
// 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
if (state == PULL_To_REFRESH) { setSelection(); // 下拉到可以进入RELEASE_TO_REFRESH的状态
if ((tempY - startY) / RATIO >= headContentHeight) {
state = RELEASE_To_REFRESH;
isBack = true;
changeHeaderViewByState(); Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
}
// 上推到顶了
else if (tempY - startY <= ) {
state = DONE;
changeHeaderViewByState(); Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
}
} // done状态下
if (state == DONE) {
if (tempY - startY > ) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
}
} // 更新headView的size
if (state == PULL_To_REFRESH) {
headView.setPadding(, - * headContentHeight
+ (tempY - startY) / RATIO, , );
} // 更新headView的paddingTop
if (state == RELEASE_To_REFRESH) {
headView.setPadding(, (tempY - startY) / RATIO
- headContentHeight, , );
}
} break;
}
} return super.onTouchEvent(event);
} // 当状态改变时候,调用该方法,以更新界面
private void changeHeaderViewByState() {
switch (state) {
case RELEASE_To_REFRESH:
progressBar.setVisibility(View.VISIBLE); Log.v(TAG, "当前状态,松开刷新");
break;
case PULL_To_REFRESH:
progressBar.setVisibility(View.VISIBLE);
// 是由RELEASE_To_REFRESH状态转变来的
if (isBack) {
isBack = false; } else {
}
Log.v(TAG, "当前状态,下拉刷新");
break; case REFRESHING: headView.setPadding(, , , ); progressBar.setVisibility(View.VISIBLE); Log.v(TAG, "当前状态,正在刷新...");
break;
case DONE:
headView.setPadding(, - * headContentHeight, , ); progressBar.setVisibility(View.GONE);
Log.v(TAG, "当前状态,done");
break;
}
} public void setOnRefreshListenerHead(
OnRefreshListenerHeader refreshListenerHeader) {
this.refreshListenerHeader = refreshListenerHeader;
isRefreshableHeader = true;
} public interface OnRefreshListenerHeader {
public void onRefresh();
} public interface OnRefreshListenerFooter {
public void onRefresh();
} public void onRefreshCompleteHeader() {
state = DONE;
changeHeaderViewByState();
} private void onRefresh() {
if (refreshListenerHeader != null) {
refreshListenerHeader.onRefresh();
}
} // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
private void measureView(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(, + , p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > ) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
} public void setAdapter(BaseAdapter adapter) {
super.setAdapter(adapter);
}
}
对应头部布局:
<?xml version="1.0" encoding="utf-8"?> <!-- ListView的头部 -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" > <View
android:id="@+id/line"
android:layout_width="0.2dip"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:background="@color/gray" /> <LinearLayout
android:id="@+id/drop_down_head"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="center_horizontal"
android:orientation="vertical" > <View
android:layout_width="0.2dip"
android:layout_height="20dip"
android:layout_gravity="center_horizontal"
android:background="@color/gray" /> <ProgressBar
android:id="@+id/loading"
android:layout_width="20dip"
android:layout_height="20dip"
android:background="@drawable/circle_shape"
android:indeterminateDrawable="@drawable/loading" />
</LinearLayout> </FrameLayout>