下拉重新整理與上拉載入更多

來源:互聯網
上載者:User

標籤:android   android開發   

代碼如下:

/** * ListView下拉重新整理和載入更多 * <p> *  * <strong>變更說明:</strong> * <p> * 預設如果設定了OnRefreshListener介面和OnLoadMoreListener介面 * <p> * 剩餘三個Flag: <br> * mIsAutoLoadMore(是否自動載入更多) <br> * mIsMoveToFirstItemAfterRefresh(下拉重新整理後是否顯示第一條Item) <br> * mIsDoRefreshOnWindowFocused(當該ListView所在的控制項顯示到螢幕上時,是否直接顯示正在重新整理...) *  * @author lee */public class MongoPullToRefreshOrLoadMoreListView extends ListView implementsOnScrollListener {/** 顯示格式化日期模板 */private final static String DATE_FORMAT_STR = "yyyy年MM月dd日 HH:mm";/** 實際的padding的距離與介面上位移距離的比例 */private final static int RATIO = 3;// ===========================以下4個常量為// 下拉重新整理的狀態標識===============================/** 鬆開重新整理 */private final static int RELEASE_TO_REFRESH = 0;/** 下拉重新整理 */private final static int PULL_TO_REFRESH = 1;/** 正在重新整理 */private final static int REFRESHING = 2;/** 重新整理完成 or 什麼都沒做,恢複原狀態。 */private final static int DONE = 3;// ===========================以下3個常量為// 載入更多的狀態標識===============================/** 載入中 */private final static int ENDINT_LOADING = 1;/** 手動完成重新整理 */private final static int ENDINT_MANUAL_LOAD_DONE = 2;/** 自動完成重新整理 */private final static int ENDINT_AUTO_LOAD_DONE = 3;/** * <strong>下拉重新整理HeadView的即時狀態flag</strong> *  * <p> * 0 : RELEASE_TO_REFRESH; * <p> * 1 : PULL_To_REFRESH; * <p> * 2 : REFRESHING; * <p> * 3 : DONE; *  */private int mHeadState;/** * <strong>載入更多FootView(EndView)的即時狀態flag</strong> *  * <p> * 0 : 完成/等待重新整理 ; * <p> * 1 : 載入中 */private int mEndState;// ================================= 功能設定Flag// ================================/** 可以載入更多否 */private boolean mCanLoadMore = false;/** 可以下拉重新整理否 */private boolean mCanRefresh = false;/** 可以自動載入更多嗎?(注意,先判斷是否有載入更多,如果沒有,這個flag也沒有意義) */private boolean mIsAutoLoadMore = false;/** 下拉重新整理後是否顯示第一條Item */private boolean mIsMoveToFirstItemAfterRefresh = false;/** 當該ListView所在的控制項顯示到螢幕上時,是否直接顯示正在重新整理... */private boolean mIsDoRefreshOnUIChanged = false;public boolean isCanLoadMore() {return mCanLoadMore;}public void setCanLoadMore(boolean pCanLoadMore) {mCanLoadMore = pCanLoadMore;if (mCanLoadMore && getFooterViewsCount() == 0) {addFooterView();} else {if (null != mEndRootView) {removeFooterView(mEndRootView);}}}public boolean isCanRefresh() {return mCanRefresh;}public void setCanRefresh(boolean pCanRefresh) {mCanRefresh = pCanRefresh;}public boolean isAutoLoadMore() {return mIsAutoLoadMore;}public void setAutoLoadMore(boolean pIsAutoLoadMore) {mIsAutoLoadMore = pIsAutoLoadMore;}public boolean isMoveToFirstItemAfterRefresh() {return mIsMoveToFirstItemAfterRefresh;}public void setMoveToFirstItemAfterRefresh(boolean pIsMoveToFirstItemAfterRefresh) {mIsMoveToFirstItemAfterRefresh = pIsMoveToFirstItemAfterRefresh;}public boolean isDoRefreshOnUIChanged() {return mIsDoRefreshOnUIChanged;}public void setDoRefreshOnUIChanged(boolean pIsDoRefreshOnWindowFocused) {mIsDoRefreshOnUIChanged = pIsDoRefreshOnWindowFocused;}// ============================================================================private LayoutInflater mInflater;private LinearLayout mHeadRootView;private TextView mTipsTextView;private TextView mLastUpdatedTextView;private ImageView mArrowImageView;private ProgressBar mProgressBar;private View mEndRootView;private ProgressBar mEndLoadProgressBar;private TextView mEndLoadTipsTextView;/** headView動畫 */private RotateAnimation mArrowAnim;/** headView反轉動畫 */private RotateAnimation mArrowReverseAnim;/** 用於保證startY的值在一個完整的touch事件中只被記錄一次 */private boolean mIsRecored;private int mHeadViewWidth;private int mHeadViewHeight;private int mStartY;private boolean mIsBack;private int mFirstItemIndex;private int mLastItemIndex;private int mCount;@SuppressWarnings("unused")private boolean mEnoughCount;// 足夠數量充滿螢幕?private OnRefreshListener mRefreshListener;private OnLoadMoreListener mLoadMoreListener;private String mLabel;public String getLabel() {return mLabel;}public void setLabel(String pLabel) {mLabel = pLabel;}public MongoPullToRefreshOrLoadMoreListView(Context pContext) {super(pContext);init(pContext);}public MongoPullToRefreshOrLoadMoreListView(Context pContext,AttributeSet pAttrs) {super(pContext, pAttrs);init(pContext);}public MongoPullToRefreshOrLoadMoreListView(Context pContext,AttributeSet pAttrs, int pDefStyle) {super(pContext, pAttrs, pDefStyle);init(pContext);}/** * 初始化操作 *  * @param pContext */private void init(Context pContext) {// final ViewConfiguration _ViewConfiguration =// ViewConfiguration.get(pContext);// mTouchSlop = _ViewConfiguration.getScaledTouchSlop();setCacheColorHint(pContext.getResources().getColor(R.color.transparent));setOnLongClickListener(null);mInflater = LayoutInflater.from(pContext);addHeadView();setOnScrollListener(this);initPullImageAnimation(0);}/** * 添加下拉重新整理的HeadView */private void addHeadView() {mHeadRootView = (LinearLayout) mInflater.inflate(R.layout.pull_to_refresh_head2, null);mArrowImageView = (ImageView) mHeadRootView.findViewById(R.id.head_arrowImageView);mArrowImageView.setMinimumWidth(70);mArrowImageView.setMinimumHeight(50);mProgressBar = (ProgressBar) mHeadRootView.findViewById(R.id.head_progressBar);mTipsTextView = (TextView) mHeadRootView.findViewById(R.id.head_tipsTextView);mLastUpdatedTextView = (TextView) mHeadRootView.findViewById(R.id.head_lastUpdatedTextView);measureView(mHeadRootView);mHeadViewHeight = mHeadRootView.getMeasuredHeight();mHeadViewWidth = mHeadRootView.getMeasuredWidth();mHeadRootView.setPadding(0, -1 * mHeadViewHeight, 0, 0);mHeadRootView.invalidate();addHeaderView(mHeadRootView, null, false);mHeadState = DONE;changeHeadViewByState();}/** * 添加載入更多FootView */private void addFooterView() {mEndRootView = mInflater.inflate(R.layout.pull_to_refresh_load_more,null);mEndRootView.setVisibility(View.VISIBLE);mEndLoadProgressBar = (ProgressBar) mEndRootView.findViewById(R.id.pull_to_refresh_progress);mEndLoadTipsTextView = (TextView) mEndRootView.findViewById(R.id.load_more);mEndRootView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mCanLoadMore) {if (mCanRefresh) {if (mEndState != ENDINT_LOADING&& mHeadState != REFRESHING) {mEndState = ENDINT_LOADING;onLoadMore();}} else if (mEndState != ENDINT_LOADING) {mEndState = ENDINT_LOADING;onLoadMore();}}}});addFooterView(mEndRootView);if (mIsAutoLoadMore) {mEndState = ENDINT_AUTO_LOAD_DONE;} else {mEndState = ENDINT_MANUAL_LOAD_DONE;}}/** * 執行個體化下拉重新整理的箭頭的動畫效果 */private void initPullImageAnimation(final int pAnimDuration) {int _Duration;if (pAnimDuration > 0) {_Duration = pAnimDuration;} else {_Duration = 250;}Interpolator _Interpolator = new LinearInterpolator();mArrowAnim = new RotateAnimation(0, -180,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);mArrowAnim.setInterpolator(_Interpolator);mArrowAnim.setDuration(_Duration);mArrowAnim.setFillAfter(true);mArrowReverseAnim = new RotateAnimation(-180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);mArrowReverseAnim.setInterpolator(_Interpolator);mArrowReverseAnim.setDuration(_Duration);mArrowReverseAnim.setFillAfter(true);}/** * 測量HeadView寬高(此方法僅適用於LinearLayout) *  * @param pChild */private void measureView(View pChild) {ViewGroup.LayoutParams p = pChild.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);}pChild.measure(childWidthSpec, childHeightSpec);}/** * 為了判斷滑動到ListView底部沒 */@Overridepublic void onScroll(AbsListView pView, int pFirstVisibleItem,int pVisibleItemCount, int pTotalItemCount) {mFirstItemIndex = pFirstVisibleItem;mLastItemIndex = pFirstVisibleItem + pVisibleItemCount - 2;mCount = pTotalItemCount - 2;if (pTotalItemCount > pVisibleItemCount) {mEnoughCount = true;} else {mEnoughCount = false;}}/** * 載入判斷。 */@Overridepublic void onScrollStateChanged(AbsListView pView, int pScrollState) {if (mCanLoadMore) {if (mLastItemIndex == mCount && pScrollState == SCROLL_STATE_IDLE) {if (mEndState != ENDINT_LOADING) {if (mIsAutoLoadMore) {if (mCanRefresh) {if (mHeadState != REFRESHING) {mEndState = ENDINT_LOADING;onLoadMore();changeEndViewByState();}} else {mEndState = ENDINT_LOADING;onLoadMore();changeEndViewByState();}} else {mEndState = ENDINT_MANUAL_LOAD_DONE;changeEndViewByState();}}}} else if (mEndRootView != null&& mEndRootView.getVisibility() == VISIBLE) {mEndRootView.setVisibility(View.GONE);this.removeFooterView(mEndRootView);}}/** * 改變載入更多狀態 */private void changeEndViewByState() {if (mCanLoadMore) {switch (mEndState) {case ENDINT_LOADING: // 重新整理中if (mEndLoadTipsTextView.getText().equals(R.string.p2refresh_doing_end_refresh)) {break;}mEndLoadTipsTextView.setText(R.string.p2refresh_doing_end_refresh);mEndLoadTipsTextView.setVisibility(View.VISIBLE);mEndLoadProgressBar.setVisibility(View.VISIBLE);break;case ENDINT_MANUAL_LOAD_DONE:// 手動重新整理完成mEndLoadTipsTextView.setText(R.string.p2refresh_end_click_load_more);mEndLoadTipsTextView.setVisibility(View.VISIBLE);mEndLoadProgressBar.setVisibility(View.GONE);mEndRootView.setVisibility(View.VISIBLE);break;case ENDINT_AUTO_LOAD_DONE:// 自動重新整理完成mEndLoadTipsTextView.setText(R.string.p2refresh_end_load_more);mEndLoadTipsTextView.setVisibility(View.VISIBLE);mEndLoadProgressBar.setVisibility(View.GONE);mEndRootView.setVisibility(View.VISIBLE);break;default:break;}}}/** * 注意事項: 此方法不適用於ViewPager中, 方法為:直接調用pull2RefreshManually(); */@Overridepublic void onWindowFocusChanged(boolean pHasWindowFocus) {super.onWindowFocusChanged(pHasWindowFocus);if (mIsDoRefreshOnUIChanged) {if (pHasWindowFocus) {pull2RefreshManually();}}}/** * 當該ListView所在的控制項顯示到螢幕上時,直接顯示正在重新整理... */public void pull2RefreshManually() {mHeadState = REFRESHING;changeHeadViewByState();onRefresh();mIsRecored = false;mIsBack = false;}/** */public boolean onTouchEvent(MotionEvent event) {if (mCanRefresh) {if (mCanLoadMore && mEndState == ENDINT_LOADING) {return super.onTouchEvent(event);}switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (mFirstItemIndex == 0 && !mIsRecored) {mIsRecored = true;mStartY = (int) event.getY();} else if (mFirstItemIndex == 0 && mIsRecored) {mStartY = (int) event.getY();}break;case MotionEvent.ACTION_UP:if (mHeadState != REFRESHING) {if (mHeadState == DONE) {}if (mHeadState == PULL_TO_REFRESH) {mHeadState = DONE;changeHeadViewByState();}if (mHeadState == RELEASE_TO_REFRESH) {mHeadState = REFRESHING;changeHeadViewByState();onRefresh();}}mIsRecored = false;mIsBack = false;break;case MotionEvent.ACTION_MOVE:int _TempY = (int) event.getY();if (!mIsRecored && mFirstItemIndex == 0) {mIsRecored = true;mStartY = _TempY;}if (mHeadState != REFRESHING && mIsRecored) {if (mHeadState == RELEASE_TO_REFRESH) {setSelection(0);if (((_TempY - mStartY) / RATIO < mHeadViewHeight)&& (_TempY - mStartY) > 0) {mHeadState = PULL_TO_REFRESH;changeHeadViewByState();} else if (_TempY - mStartY <= 0) {mHeadState = DONE;changeHeadViewByState();}}if (mHeadState == PULL_TO_REFRESH) {setSelection(0);if ((_TempY - mStartY) / RATIO >= mHeadViewHeight) {mHeadState = RELEASE_TO_REFRESH;mIsBack = true;changeHeadViewByState();} else if (_TempY - mStartY <= 0) {mHeadState = DONE;changeHeadViewByState();}}if (mHeadState == DONE) {if (_TempY - mStartY > 0) {mHeadState = PULL_TO_REFRESH;changeHeadViewByState();}}if (mHeadState == PULL_TO_REFRESH) {mHeadRootView.setPadding(0, -1 * mHeadViewHeight+ (_TempY - mStartY) / RATIO, 0, 0);}if (mHeadState == RELEASE_TO_REFRESH) {mHeadRootView.setPadding(0, (_TempY - mStartY) / RATIO- mHeadViewHeight, 0, 0);}}break;}}return super.onTouchEvent(event);}/** * 當HeadView狀態改變時候,調用該方法,以更新介面 */private void changeHeadViewByState() {switch (mHeadState) {case RELEASE_TO_REFRESH:mArrowImageView.setVisibility(View.VISIBLE);mProgressBar.setVisibility(View.GONE);mTipsTextView.setVisibility(View.VISIBLE);// mLastUpdatedTextView.setVisibility(View.VISIBLE);mArrowImageView.clearAnimation();mArrowImageView.startAnimation(mArrowAnim);mTipsTextView.setText(R.string.p2refresh_release_refresh);break;case PULL_TO_REFRESH:mProgressBar.setVisibility(View.GONE);mTipsTextView.setVisibility(View.VISIBLE);// mLastUpdatedTextView.setVisibility(View.VISIBLE);mArrowImageView.clearAnimation();mArrowImageView.setVisibility(View.VISIBLE);if (mIsBack) {mIsBack = false;mArrowImageView.clearAnimation();mArrowImageView.startAnimation(mArrowReverseAnim);mTipsTextView.setText(R.string.p2refresh_pull_to_refresh);} else {mTipsTextView.setText(R.string.p2refresh_pull_to_refresh);}break;case REFRESHING:changeHeaderViewRefreshState();break;case DONE:mHeadRootView.setPadding(0, -1 * mHeadViewHeight, 0, 0);mProgressBar.setVisibility(View.GONE);mArrowImageView.clearAnimation();// mArrowImageView.setImageResource(R.drawable.pulltorefresh_arrow);mArrowImageView.setImageResource(R.drawable.arrow_gray);mTipsTextView.setText(R.string.p2refresh_pull_to_refresh);mLastUpdatedTextView.setVisibility(View.GONE);break;}}/** * 改變HeadView在重新整理狀態下的顯示 */private void changeHeaderViewRefreshState() {mHeadRootView.setPadding(0, 0, 0, 0);mProgressBar.setVisibility(View.VISIBLE);mArrowImageView.clearAnimation();mArrowImageView.setVisibility(View.GONE);mTipsTextView.setText(R.string.p2refresh_doing_head_refresh);mLastUpdatedTextView.setVisibility(View.VISIBLE);}/** * 下拉重新整理監聽介面 */public interface OnRefreshListener {public void onRefresh();}/** * 載入更多監聽介面 */public interface OnLoadMoreListener {public void onLoadMore();}public void setOnRefreshListener(OnRefreshListener pRefreshListener) {if (pRefreshListener != null) {mRefreshListener = pRefreshListener;mCanRefresh = true;}}public void setOnLoadListener(OnLoadMoreListener pLoadMoreListener) {if (pLoadMoreListener != null) {mLoadMoreListener = pLoadMoreListener;mCanLoadMore = true;if (mCanLoadMore && getFooterViewsCount() == 0) {addFooterView();}}}/** * 正在下拉重新整理 */private void onRefresh() {if (mRefreshListener != null) {mRefreshListener.onRefresh();}}/** * 下拉重新整理完成 */public void onRefreshComplete() {mHeadState = DONE;mLastUpdatedTextView.setText(getResources().getString(R.string.p2refresh_refresh_lasttime)+ new SimpleDateFormat(DATE_FORMAT_STR, Locale.CHINA).format(new Date()));changeHeadViewByState();if (mIsMoveToFirstItemAfterRefresh) {mFirstItemIndex = 0;setSelection(0);}}/** * 正在載入更多,FootView顯示 : 載入中... */private void onLoadMore() {if (mLoadMoreListener != null) {mEndLoadTipsTextView.setText(R.string.p2refresh_doing_end_refresh);mEndLoadTipsTextView.setVisibility(View.VISIBLE);mEndLoadProgressBar.setVisibility(View.VISIBLE);mLoadMoreListener.onLoadMore();}}/** * 載入更多完成 */public void onLoadMoreComplete() {if (mIsAutoLoadMore) {mEndState = ENDINT_AUTO_LOAD_DONE;} else {mEndState = ENDINT_MANUAL_LOAD_DONE;}changeEndViewByState();}/** * 主要更新一下重新整理時間啦! */public void setAdapter(BaseAdapter adapter) {mLastUpdatedTextView.setText(getResources().getString(R.string.p2refresh_refresh_lasttime)+ new SimpleDateFormat(DATE_FORMAT_STR, Locale.CHINA).format(new Date()));super.setAdapter(adapter);}public void setEndRootViewVisibility(boolean b) {if (mEndRootView == null) {return;}if (getFooterViewsCount() == 0 && b) {addFooterView();} else {removeFooterView(mEndRootView);}}public View getFooterView() {return mEndRootView;}}


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.