package czd.lib.view.abslistview.pull; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.*; import android.widget.AbsListView.OnScrollListener; import czd.lib.R; import czd.lib.view.ViewUtil; public class PullListView extends ListView implements OnScrollListener { public static final int STATE_RELEASETOREFRESH = 0; public static final int STATE_PULLTOREFRESH = 1; public static final int STATE_REFRESHING = 2; public static final int STATE_DONE = 3; private static final int RATIO = 3; private boolean onTop = true, onBottom = true; private LinearLayout header; private String _headerStatePull; private String _headerStateRelease; private String _headerStateLoading; private String _headerStateDone; private Drawable _headerBackground; private int _headerTextColor; private int _headerInfoVisible; private ImageView header_iv; private ProgressBar header_pb; private TextView header_stv; private TextView header_itv; private Animation anim_up; private Animation anim_down; private int firstVisibleItem; private int state = STATE_DONE; private boolean refreshable = false; private boolean pulling = true; private int startY = 0; private boolean isback = false; private AbsListPullListener listener; private int m = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); private int header_height = 0; public PullListView(Context context) { super(context); init(context, null); } public PullListView(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public PullListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs); } private void init(Context context, AttributeSet attrs) { if (attrs != null) { TypedArray tattrs = context.obtainStyledAttributes(attrs, R.styleable.PullView); this._headerStatePull = tattrs.getString(0); this._headerStateRelease = tattrs.getString(1); this._headerStateLoading = tattrs.getString(2); this._headerStateDone = tattrs.getString(3); this._headerBackground = tattrs.getDrawable(4); this._headerTextColor = tattrs.getInt(5, android.R.color.black); this._headerInfoVisible = tattrs.getInt(6, View.VISIBLE); tattrs.recycle(); } this.header = (LinearLayout)ViewUtil.viewById(context, R.layout.common_pull_header); this.header_iv = (ImageView)this.header.findViewById(R.id.common_pull_header_image); this.header_pb = (ProgressBar)this.header.findViewById(R.id.common_pull_header_progress); this.header_stv = (TextView)this.header.findViewById(R.id.common_pull_header_state); this.header_itv = (TextView)this.header.findViewById(R.id.common_pull_header_info); this.header.setBackgroundDrawable(this._headerBackground); this.header_iv.setVisibility(View.VISIBLE); this.header_pb.setVisibility(View.VISIBLE); this.header_stv.setTextColor(_headerTextColor); this.header_itv.setTextColor(_headerTextColor); this.header_itv.setVisibility(_headerInfoVisible); header.measure(m, m); header_height = header.getMeasuredHeight(); this.header.setPadding(0, -1 * header_height, 0, 0); header.invalidate(); addHeaderView(this.header, null, false); setOnScrollListener(this); this.anim_up = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); this.anim_up.setInterpolator(new LinearInterpolator()); this.anim_up.setDuration(250); this.anim_up.setFillAfter(true); this.anim_down = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); this.anim_down.setInterpolator(new LinearInterpolator()); this.anim_down.setDuration(200); this.anim_down.setFillAfter(true); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { this.listener.onScrollStateChanged(view, scrollState); } @Override public final boolean onInterceptTouchEvent(MotionEvent event) { if (refreshable) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (state != STATE_REFRESHING && firstVisibleItem == 0) { startY = (int)event.getY(); } } } return super.onInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent ev) { if (refreshable) { switch (ev.getAction()) { case MotionEvent.ACTION_UP: if (startY != 0) { if (state != STATE_REFRESHING) { switch (state) { case STATE_PULLTOREFRESH: state = STATE_DONE; resetHeader(); break; case STATE_RELEASETOREFRESH: state = STATE_REFRESHING; resetHeader(); onRefresh(); break; default: break; } } isback = false; startY = 0; } pulling = false; break; case MotionEvent.ACTION_MOVE: if (state != STATE_REFRESHING && firstVisibleItem == 0 && startY > 0) { int tmpY = (int)ev.getY(); switch (state) { case STATE_RELEASETOREFRESH: pulling = true; setSelection(0); if (tmpY <= startY) { state = STATE_DONE; resetHeader(); } else if ((tmpY - startY) / RATIO < header_height) { state = STATE_PULLTOREFRESH; resetHeader(); } break; case STATE_PULLTOREFRESH: pulling = true; setSelection(0); if (tmpY <= startY) { state = STATE_DONE; resetHeader(); } else if ((tmpY - startY) / RATIO >= header_height) { state = STATE_RELEASETOREFRESH; isback = true; resetHeader(); } break; case STATE_DONE: if (tmpY > startY) { state = STATE_PULLTOREFRESH; resetHeader(); pulling = true; } else { startY = 0; } break; default: break; } if (pulling && (state == STATE_PULLTOREFRESH || state == STATE_RELEASETOREFRESH)) { header.setPadding(0, (tmpY - startY) / RATIO - header_height, 0, 0); } } break; } } return super.onTouchEvent(ev); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.firstVisibleItem = firstVisibleItem; if (pulling) { setSelection(0); } if (this.listener != null) { this.listener.onScrollStop(view, firstVisibleItem, visibleItemCount, totalItemCount); } whereami(firstVisibleItem, visibleItemCount, totalItemCount); } private void whereami(int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (firstVisibleItem <= 2) { if (!onTop && this.listener != null) { onTop = true; listener.onTop(firstVisibleItem, visibleItemCount, totalItemCount); } } else { if (onTop && listener != null) { onTop = false; listener.outTop(firstVisibleItem, visibleItemCount, totalItemCount); } } if (totalItemCount - visibleItemCount - firstVisibleItem + 1 <= 2) { if (!onBottom && listener != null) { onBottom = true; listener.onBottom(firstVisibleItem, visibleItemCount, totalItemCount); } } else { if (onBottom && listener != null) { onBottom = false; listener.outBottom(firstVisibleItem, visibleItemCount, totalItemCount); } } } public int getHeaderState() { return state; } public void setHeaderInfo(String text) { this.header_itv.setText(text); if (this.header_itv.getVisibility() != View.VISIBLE) { this.header_itv.setVisibility(View.VISIBLE); } } public void setHeaderInfoVisible(int visible) { this.header_itv.setVisibility(visible); } public void setPullListener(AbsListPullListener listener) { this.listener = listener; this.refreshable = true; } public void setHeaderDone() { state = STATE_DONE; resetHeader(); invalidateViews(); setSelection(0); } private void onRefresh() { if (listener != null) { listener.onRefresh(); } } private void resetHeader() { switch (state) { case STATE_DONE: this.header_stv.setText(_headerStateDone); this.header.setPadding(0, -1 * header_height, 0, 0); this.header_pb.setVisibility(View.GONE); this.header_iv.clearAnimation(); this.header_iv.setVisibility(View.VISIBLE); break; case STATE_PULLTOREFRESH: this.header_stv.setText(_headerStatePull); this.header_pb.setVisibility(View.GONE); this.header_iv.setVisibility(View.VISIBLE); if (isback) { isback = false; this.header_iv.clearAnimation(); this.header_iv.startAnimation(anim_down); } break; case STATE_RELEASETOREFRESH: this.header_stv.setText(_headerStateRelease); this.header_pb.setVisibility(View.GONE); this.header_iv.setVisibility(View.VISIBLE); this.header_iv.clearAnimation(); this.header_iv.startAnimation(anim_up); break; case STATE_REFRESHING: this.header.setPadding(0, 0, 0, 0); this.header_stv.setText(_headerStateLoading); this.header_iv.clearAnimation(); this.header_iv.setVisibility(View.GONE); this.header_pb.setVisibility(View.VISIBLE); break; default: break; } } }