package com.hyrt.cei.ui.ebook.view; import java.util.Date; import com.hyrt.cei.R; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.ScrollView; import android.widget.TextView; public class CustomScrollView extends ScrollView { private final static int RELEASE_To_REFRESH = 0; private final static int PULL_To_REFRESH = 1; private final static int REFRESHING = 2; private final static int DONE = 3; private final static int LOADING = 4; private ViewGroup parentView = null; private LinearLayout headView = null; private LinearLayout footView = null; private TextView tipsTextview;// 下拉刷新 private TextView lastUpdatedTextView;// 最新更新 private ImageView arrowImageView;// 箭头 private ProgressBar progressBar;// 刷新进度条 private ProgressBar moreProgressBar; private TextView loadMoreView; private RotateAnimation animation;// 旋转特效 刷新中箭头翻转 向下变向上 private RotateAnimation reverseAnimation; // 箭头向上变向下 private int headContentHeight;// 头部高度 private boolean isRecored; private int startY;// 高度起始位置,用来记录与头部距离 private int state;// 下拉刷新中、松开刷新中、正在刷新中、完成刷新 private boolean isBack; private boolean isSeeHead; private boolean isScroll; // 判断是否有滑动 private final static int RATIO = 3; // 实际的padding的距离与界面上偏移距离的比例 private OnRefreshListener refreshListener; private OnLoadListener loadListener; public CustomScrollView(Context context) { super(context); initView(context); } public CustomScrollView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public CustomScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(context); } public void initView(Context context) { LayoutInflater inflater = LayoutInflater.from(context); headView = (LinearLayout) inflater.inflate(R.layout.header, null); footView = (LinearLayout) inflater.inflate(R.layout.listfooter_more, null); arrowImageView = (ImageView) headView .findViewById(R.id.head_arrowImageView); arrowImageView.setMinimumWidth(70); arrowImageView.setMinimumHeight(50); progressBar = (ProgressBar) headView .findViewById(R.id.head_progressBar); tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView); lastUpdatedTextView = (TextView) headView .findViewById(R.id.head_lastUpdatedTextView); moreProgressBar = (ProgressBar) footView .findViewById(R.id.pull_to_refresh_progress); loadMoreView = (TextView) footView.findViewById(R.id.load_more); measureView(headView); headContentHeight = headView.getMeasuredHeight(); animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); animation.setInterpolator(new LinearInterpolator()); animation.setDuration(250); animation.setFillAfter(true); reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); reverseAnimation.setInterpolator(new LinearInterpolator()); reverseAnimation.setDuration(200); reverseAnimation.setFillAfter(true); state = DONE; isRecored = false; isSeeHead = false; isScroll = false; } 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(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } @Override public boolean onTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub if (parentView == null) { parentView = (ViewGroup) this.getChildAt(0); headView.setPadding(0, -1 * headContentHeight, 0, 0); headView.invalidate(); parentView.addView(headView, 0); parentView.addView(footView); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: if (this.getScrollY() == 0 && !isRecored) { startY = (int) ev.getY(); isRecored = true; } break; case MotionEvent.ACTION_MOVE: int tempY = (int) ev.getY(); if (!isScroll) isScroll = true; if (!isRecored && this.getScrollY() == 0) { isRecored = true; startY = tempY; } if (tempY - startY < 0) { startY = tempY; } if (state != REFRESHING && state != LOADING && isRecored) { if (state == RELEASE_To_REFRESH) { if ((tempY - startY) > 0 && (tempY - startY) / RATIO < headContentHeight + 10) { state = PULL_To_REFRESH; changeHeaderViewByState(); } else if (tempY - startY <= 0) { state = DONE; changeHeaderViewByState(); } } if (state == PULL_To_REFRESH) { if ((tempY - startY) / RATIO >= headContentHeight + 10) { state = RELEASE_To_REFRESH; isBack = true; changeHeaderViewByState(); } else if (tempY - startY <= 0) { state = DONE; changeHeaderViewByState(); } } if (state == DONE) { if (tempY - startY > 0) { state = PULL_To_REFRESH; changeHeaderViewByState(); isSeeHead = true; } } if (state == RELEASE_To_REFRESH) { headView.setPadding(0, (tempY - startY) / RATIO - headContentHeight, 0, 0); headView.invalidate(); } else if (state == PULL_To_REFRESH) { headView.setPadding(0, -1 * headContentHeight + (tempY - startY) / RATIO, 0, 0); headView.invalidate(); } } break; case MotionEvent.ACTION_UP: if (state == PULL_To_REFRESH) { state = DONE; changeHeaderViewByState(); } if (state == RELEASE_To_REFRESH) { state = REFRESHING; changeHeaderViewByState(); onRefresh(); } isRecored = false; isSeeHead = false; isBack = false; if (parentView != null) { int viewHeight = parentView.getHeight(); int y = this.getScrollY(); if ((viewHeight - y - this.getHeight()) == 0 && isScroll && state != REFRESHING && state != LOADING) { onLoad(); } } isScroll = false; break; } if (isSeeHead) { return true; } else { return super.onTouchEvent(ev); } } private void changeHeaderViewByState() { switch (state) { case RELEASE_To_REFRESH: arrowImageView.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); tipsTextview.setVisibility(View.VISIBLE); lastUpdatedTextView.setVisibility(View.VISIBLE); arrowImageView.clearAnimation(); arrowImageView.startAnimation(animation); tipsTextview.setText("松开刷新"); break; case PULL_To_REFRESH: progressBar.setVisibility(View.GONE); tipsTextview.setVisibility(View.VISIBLE); lastUpdatedTextView.setVisibility(View.VISIBLE); arrowImageView.clearAnimation(); arrowImageView.setVisibility(View.VISIBLE); // 是由RELEASE_To_REFRESH状态转变来的 if (isBack) { isBack = false; arrowImageView.clearAnimation(); arrowImageView.startAnimation(reverseAnimation); } tipsTextview.setText("下拉刷新"); break; case REFRESHING: headView.setPadding(0, 0, 0, 0); progressBar.setVisibility(View.VISIBLE); arrowImageView.clearAnimation(); arrowImageView.setVisibility(View.GONE); tipsTextview.setText("正在刷新..."); lastUpdatedTextView.setVisibility(View.VISIBLE); break; case DONE: headView.setPadding(0, -1 * headContentHeight, 0, 0); progressBar.setVisibility(View.GONE); arrowImageView.clearAnimation(); arrowImageView.setImageResource(R.drawable.arrow); tipsTextview.setText("下拉刷新"); lastUpdatedTextView.setVisibility(View.VISIBLE); isRecored = false; break; } } public void setOnRefreshListener(OnRefreshListener refreshListener) { this.refreshListener = refreshListener; } public interface OnRefreshListener { public void onRefresh(); } private void onRefresh() { if (refreshListener != null) { refreshListener.onRefresh(); } } public void onRefreshComplete() { state = DONE; lastUpdatedTextView.setText("上次刷新:" + new Date().toLocaleString()); changeHeaderViewByState(); } public void setOnLoadListener(OnLoadListener loadListener) { this.loadListener = loadListener; } public interface OnLoadListener { public void onLoad(); } private void onLoad() { if (loadListener != null) { state = LOADING; footView.setVisibility(View.VISIBLE); moreProgressBar.setVisibility(View.VISIBLE); loadMoreView.setText("正在加载..."); loadListener.onLoad(); } } public void onLoadComplete() { state = DONE; moreProgressBar.setVisibility(View.GONE); loadMoreView.setText("查看更多"); footView.setVisibility(View.INVISIBLE); } }