Android 下拉重新整理,上拉載入更多控制項–支援ListView,GridView和ScrollView

來源:互聯網
上載者:User

麥洛原文:http://miloisbadboy.com/archives/55

由於這個文章比較長點,這裡簡單貼點代碼,詳細說明還是看原文吧

 

 

 

主要源碼

package com.miloisbadboy.view;import android.content.Context;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;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.AdapterView;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ProgressBar;import android.widget.ScrollView;import android.widget.TextView;import com.miloisbadboy.R;public class PullToRefreshView extends LinearLayout {private static final String TAG = "PullToRefreshView";// refresh statesprivate static final int PULL_TO_REFRESH = 2;private static final int RELEASE_TO_REFRESH = 3;private static final int REFRESHING = 4;// pull stateprivate static final int PULL_UP_STATE = 0;private static final int PULL_DOWN_STATE = 1;/** * last y */private int mLastMotionY;/** * lock */private boolean mLock;/** * header view */private View mHeaderView;/** * footer view */private View mFooterView;/** * list or grid */private AdapterView<?> mAdapterView;/** * scrollview */private ScrollView mScrollView;/** * header view height */private int mHeaderViewHeight;/** * footer view height */private int mFooterViewHeight;/** * header view image */private ImageView mHeaderImageView;/** * footer view image */private ImageView mFooterImageView;/** * header tip text */private TextView mHeaderTextView;/** * footer tip text */private TextView mFooterTextView;/** * header refresh time */private TextView mHeaderUpdateTextView;/** * footer refresh time */// private TextView mFooterUpdateTextView;/** * header progress bar */private ProgressBar mHeaderProgressBar;/** * footer progress bar */private ProgressBar mFooterProgressBar;/** * layout inflater */private LayoutInflater mInflater;/** * header view current state */private int mHeaderState;/** * footer view current state */private int mFooterState;/** * pull state,pull up or pull down;PULL_UP_STATE or PULL_DOWN_STATE */private int mPullState;/** * 變為向下的箭頭,改變箭頭方向 */private RotateAnimation mFlipAnimation;/** * 變為逆向的箭頭,旋轉 */private RotateAnimation mReverseFlipAnimation;/** * footer refresh listener */private OnFooterRefreshListener mOnFooterRefreshListener;/** * footer refresh listener */private OnHeaderRefreshListener mOnHeaderRefreshListener;/** * last update time */private String mLastUpdateTime;public PullToRefreshView(Context context, AttributeSet attrs) {super(context, attrs);init();}public PullToRefreshView(Context context) {super(context);init();}/** * init *  * @description * @param context */private void init() {// Load all of the animations we need in code rather than through XMLmFlipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);mFlipAnimation.setInterpolator(new LinearInterpolator());mFlipAnimation.setDuration(250);mFlipAnimation.setFillAfter(true);mReverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF,0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);mReverseFlipAnimation.setInterpolator(new LinearInterpolator());mReverseFlipAnimation.setDuration(250);mReverseFlipAnimation.setFillAfter(true);mInflater = LayoutInflater.from(getContext());// header view 在此添加,保證是第一個添加到linearlayout的最上端addHeaderView();}private void addHeaderView() {// header viewmHeaderView = mInflater.inflate(R.layout.refresh_header, this, false);mHeaderImageView = (ImageView) mHeaderView.findViewById(R.id.pull_to_refresh_image);mHeaderTextView = (TextView) mHeaderView.findViewById(R.id.pull_to_refresh_text);mHeaderUpdateTextView = (TextView) mHeaderView.findViewById(R.id.pull_to_refresh_updated_at);mHeaderProgressBar = (ProgressBar) mHeaderView.findViewById(R.id.pull_to_refresh_progress);// header layoutmeasureView(mHeaderView);mHeaderViewHeight = mHeaderView.getMeasuredHeight();LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeaderViewHeight);// 設定topMargin的值為負的header View高度,即將其隱藏在最上方params.topMargin = -(mHeaderViewHeight);// mHeaderView.setLayoutParams(params1);addView(mHeaderView, params);}private void addFooterView() {// footer viewmFooterView = mInflater.inflate(R.layout.refresh_footer, this, false);mFooterImageView = (ImageView) mFooterView.findViewById(R.id.pull_to_load_image);mFooterTextView = (TextView) mFooterView.findViewById(R.id.pull_to_load_text);mFooterProgressBar = (ProgressBar) mFooterView.findViewById(R.id.pull_to_load_progress);// footer layoutmeasureView(mFooterView);mFooterViewHeight = mFooterView.getMeasuredHeight();LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mFooterViewHeight);//int top = getHeight();//params.topMargin =getHeight();//在這裡getHeight()==0,但在onInterceptTouchEvent()方法裡getHeight()已經有值了,不再是0;// getHeight()什麼時候會賦值,稍候再研究一下// 由於是線性布局可以直接添加,只要AdapterView的高度是MATCH_PARENT,那麼footer view就會被添加到最後,並隱藏addView(mFooterView, params);}@Overrideprotected void onFinishInflate() {super.onFinishInflate();// footer view 在此添加保證添加到linearlayout中的最後addFooterView();initContentAdapterView();}/** * init AdapterView like ListView,GridView and so on;or init ScrollView *  */private void initContentAdapterView() {int count = getChildCount();if (count < 3) {throw new IllegalArgumentException("this layout must contain 3 child views,and AdapterView or ScrollView must in the second position!");}View view = null;for(int i=0;i<count-1;++i){view = getChildAt(i);if (view instanceof AdapterView<?>) {mAdapterView = (AdapterView<?>) view;}if (view instanceof ScrollView) {// finish latermScrollView = (ScrollView)view;}}if (mAdapterView == null && mScrollView==null) {throw new IllegalArgumentException("must contain a AdapterView or ScrollView in this layout!");}}private void measureView(View child) {ViewGroup.LayoutParams p = child.getLayoutParams();if (p == null) {p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_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);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent e) {int y = (int) e.getRawY();switch (e.getAction()) {case MotionEvent.ACTION_DOWN:// 首先攔截down事件,記錄y座標mLastMotionY = y;break;case MotionEvent.ACTION_MOVE:// deltaY > 0 是向下運動,< 0是向上運動int deltaY = y - mLastMotionY;if (isRefreshViewScroll(deltaY)) {return true;}break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:break;}return false;}/* * 如果在onInterceptTouchEvent()方法中沒有攔截(即onInterceptTouchEvent()方法中 return * false)則由PullToRefreshView 的子View來處理;否則由下面的方法來處理(即由PullToRefreshView自己來處理) */@Overridepublic boolean onTouchEvent(MotionEvent event) {if (mLock) {return true;}int y = (int) event.getRawY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// onInterceptTouchEvent已經記錄// mLastMotionY = y;break;case MotionEvent.ACTION_MOVE:int deltaY = y - mLastMotionY;if (mPullState == PULL_DOWN_STATE) {// PullToRefreshView執行下拉Log.i(TAG, " pull down!parent view move!");headerPrepareToRefresh(deltaY);// setHeaderPadding(-mHeaderViewHeight);} else if (mPullState == PULL_UP_STATE) {// PullToRefreshView執行上拉Log.i(TAG, "pull up!parent view move!");footerPrepareToRefresh(deltaY);}mLastMotionY = y;break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:int topMargin = getHeaderTopMargin();if (mPullState == PULL_DOWN_STATE) {if (topMargin >= 0) {// 開始重新整理headerRefreshing();} else {// 還沒有執行重新整理,重新隱藏setHeaderTopMargin(-mHeaderViewHeight);}} else if (mPullState == PULL_UP_STATE) {if(Math.abs(topMargin)>=mHeaderViewHeight+mFooterViewHeight){// 開始執行footer 重新整理footerRefreshing();} else {// 還沒有執行重新整理,重新隱藏setHeaderTopMargin(-mHeaderViewHeight);}}break;}return super.onTouchEvent(event);}/** * 是否應該到了父View,即PullToRefreshView滑動 *  * @param deltaY *            , deltaY > 0 是向下運動,< 0是向上運動 * @return */private boolean isRefreshViewScroll(int deltaY) {if (mHeaderState == REFRESHING || mFooterState == REFRESHING) {return false;}//對於ListView 以及GridViewif (mAdapterView != null) {View child = mAdapterView.getChildAt(0);if (child == null) {// 如果mAdapterView中沒有資料,不攔截// 可以考慮返回truereturn false;}// 子view(ListView or GridView)滑動到最頂端if (deltaY > 0 && child.getTop() == 0) {mPullState = PULL_DOWN_STATE;return true;} else if (deltaY < 0) {View lastChild = mAdapterView.getChildAt(mAdapterView.getChildCount() - 1);if (lastChild == null) {// 如果mAdapterView中沒有資料,不攔截return false;}// 最後一個子view的Bottom小於父View的高度說明mAdapterView的資料沒有填滿父view,// 等於父View的高度說明mAdapterView已經滑動到最後if (lastChild.getBottom() <= getHeight()) {mPullState = PULL_UP_STATE;return true;}}}//對於ScrollViewif(mScrollView!=null){// 子scroll view滑動到最頂端View child = mScrollView.getChildAt(0);if (deltaY > 0 && mScrollView.getScrollY() == 0) {mPullState = PULL_DOWN_STATE;return true;} else if (deltaY < 0 && child.getMeasuredHeight()<=getHeight()+mScrollView.getScrollY()) {mPullState = PULL_UP_STATE;return true;}}return false;}/** * header 準備重新整理,手指移動過程,還沒有釋放 *  * @param deltaY *            ,手指滑動的距離 */private void headerPrepareToRefresh(int deltaY) {int newTopMargin = changingHeaderViewTopMargin(deltaY);// 當header view的topMargin>=0時,說明已經完全顯示出來了,修改header view 的提示狀態if (newTopMargin >= 0 && mHeaderState != RELEASE_TO_REFRESH) {mHeaderTextView.setText(R.string.pull_to_refresh_release_label);mHeaderUpdateTextView.setVisibility(View.VISIBLE);mHeaderImageView.clearAnimation();mHeaderImageView.startAnimation(mFlipAnimation);mHeaderState = RELEASE_TO_REFRESH;}}/** * footer 準備重新整理,手指移動過程,還沒有釋放 移動footer view高度同樣和移動header view * 高度是一樣,都是通過修改header view的topmargin的值來達到 *  * @param deltaY *            ,手指滑動的距離 */private void footerPrepareToRefresh(int deltaY) {int newTopMargin = changingHeaderViewTopMargin(deltaY);//如果header view topMargin 的絕對值大於或等於header + footer 的高度//說明footer view 完全顯示出來了,修改footer view 的提示狀態if(Math.abs(newTopMargin)>=(mHeaderViewHeight+mFooterViewHeight)&& mFooterState != RELEASE_TO_REFRESH){mFooterTextView.setText(R.string.pull_to_refresh_footer_release_label);mFooterImageView.clearAnimation();mFooterImageView.startAnimation(mFlipAnimation);mFooterState = RELEASE_TO_REFRESH;}}/** * 修改Header view top margin的值 * @description  * @param deltaY * @return */private int changingHeaderViewTopMargin(int deltaY){LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();float newTopMargin = params.topMargin + deltaY * 0.3f;params.topMargin = (int) newTopMargin;mHeaderView.setLayoutParams(params);invalidate();return params.topMargin;}/** * header refreshing *  */private void headerRefreshing() {mHeaderState = REFRESHING;setHeaderTopMargin(0);mHeaderImageView.setVisibility(View.GONE);mHeaderImageView.clearAnimation();mHeaderImageView.setImageDrawable(null);mHeaderProgressBar.setVisibility(View.VISIBLE);mHeaderTextView.setText(R.string.pull_to_refresh_refreshing_label);if (mOnHeaderRefreshListener != null) {mOnHeaderRefreshListener.onHeaderRefresh(this);}}/** * footer refreshing *  */private void footerRefreshing() {mFooterState = REFRESHING;int top = mHeaderViewHeight + mFooterViewHeight;setHeaderTopMargin(-top);mFooterImageView.setVisibility(View.GONE);mFooterImageView.clearAnimation();mFooterImageView.setImageDrawable(null);mFooterProgressBar.setVisibility(View.VISIBLE);mFooterTextView.setText(R.string.pull_to_refresh_footer_refreshing_label);if (mOnFooterRefreshListener != null) {mOnFooterRefreshListener.onFooterRefresh(this);}}/** * 設定header view 的topMargin的值 *  * @description * @param topMargin *            ,為0時,說明header view 剛好完全顯示出來; 為-mHeaderViewHeight時,說明完全隱藏了 */private void setHeaderTopMargin(int topMargin) {LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();params.topMargin = topMargin;mHeaderView.setLayoutParams(params);invalidate();}/** * header view 完成更新後恢複初始狀態 *  */public void onHeaderRefreshComplete() {setHeaderTopMargin(-mHeaderViewHeight);mHeaderImageView.setVisibility(View.VISIBLE);mHeaderImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow);mHeaderTextView.setText(R.string.pull_to_refresh_pull_label);mHeaderProgressBar.setVisibility(View.GONE);// mHeaderUpdateTextView.setText("");mHeaderState = PULL_TO_REFRESH;}/**     * Resets the list to a normal state after a refresh.     * @param lastUpdated Last updated at.     */    public void onHeaderRefreshComplete(CharSequence lastUpdated) {        setLastUpdated(lastUpdated);        onHeaderRefreshComplete();    }/** * footer view 完成更新後恢複初始狀態 */public void onFooterRefreshComplete() {setHeaderTopMargin(-mHeaderViewHeight);mFooterImageView.setVisibility(View.VISIBLE);mFooterImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow_up);mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label);mFooterProgressBar.setVisibility(View.GONE);// mHeaderUpdateTextView.setText("");mFooterState = PULL_TO_REFRESH;}/**     * Set a text to represent when the list was last updated.      * @param lastUpdated Last updated at.     */    public void setLastUpdated(CharSequence lastUpdated) {        if (lastUpdated != null) {            mHeaderUpdateTextView.setVisibility(View.VISIBLE);            mHeaderUpdateTextView.setText(lastUpdated);        } else {        mHeaderUpdateTextView.setVisibility(View.GONE);        }    }/** * 擷取當前header view 的topMargin *  * @description */private int getHeaderTopMargin() {LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();return params.topMargin;}/** * lock *  */private void lock() {mLock = true;}/** * unlock *  */private void unlock() {mLock = false;}/** * set headerRefreshListener *  * @description * @param headerRefreshListener */public void setOnHeaderRefreshListener(OnHeaderRefreshListener headerRefreshListener) {mOnHeaderRefreshListener = headerRefreshListener;}public void setOnFooterRefreshListener(OnFooterRefreshListener footerRefreshListener) {mOnFooterRefreshListener = footerRefreshListener;}/** * Interface definition for a callback to be invoked when list/grid footer * view should be refreshed. */public interface OnFooterRefreshListener {public void onFooterRefresh(PullToRefreshView view);}/** * Interface definition for a callback to be invoked when list/grid header * view should be refreshed. */public interface OnHeaderRefreshListener {public void onHeaderRefresh(PullToRefreshView view);}}

  

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.