Android自定义ListView实现下拉刷新列表

jopen 10年前

效果图:

Android自定义ListView实现下拉刷新列表

下面看一下实现过程:

主Activity:

    package com.example.pulltorefreshlistview;                import java.util.ArrayList;        import java.util.List;                import android.support.v7.app.ActionBarActivity;        import android.os.AsyncTask;        import android.os.Bundle;        import android.view.Menu;        import android.view.MenuItem;        import android.widget.ArrayAdapter;        import android.widget.ListView;        import android.widget.Toast;                public class Main extends ActionBarActivity {            private int m = 1;                    @Override            protected void onCreate(Bundle savedInstanceState) {                super.onCreate(savedInstanceState);                setContentView(R.layout.main);                         final AlexListView listView = (AlexListView) findViewById(R.id.mylist);                 final List<String> adapterData = new ArrayList<String>();                       for (int i = 0; i < 20; i++) {                          adapterData.add("ListItem" + i);                       }                        final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,                       android.R.layout.simple_list_item_1, adapterData);                       listView.setAdapter(adapter);                                  listView.setonRefreshListener(new AlexListView.OnRefreshListener() {                    @Override                    public void onRefresh() {                                new AsyncTask<Void, Void, Void>() { //刷新过程中需要做的操作在这里                         protected Void doInBackground(Void... params) { try {                          Thread.sleep(1000); } catch (Exception e) {                          e.printStackTrace(); }                          adapterData.add("New ListItem"+m);                          m++;                         return null; }                         //刷新完成后要通知listview进行界面调整                         @Override                          protected void onPostExecute(Void result) {                          adapter.notifyDataSetChanged();                           listView.onRefreshComplete();                         }                    }.execute();                                            }                });            }                    @Override            public boolean onCreateOptionsMenu(Menu menu) {                getMenuInflater().inflate(R.menu.main, menu);                return true;            }                    @Override            public boolean onOptionsItemSelected(MenuItem item) {                int id = item.getItemId();                if (id == R.id.action_settings) {                    return true;                }                return super.onOptionsItemSelected(item);            }        }  

自定义的ListView:
    package com.example.pulltorefreshlistview;                import java.util.Date;                import android.content.Context;        import android.graphics.Color;        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.view.animation.LinearInterpolator;        import android.view.animation.RotateAnimation;        import android.widget.AbsListView;        import android.widget.BaseAdapter;        import android.widget.ImageView;        import android.widget.LinearLayout;        import android.widget.ListView;        import android.widget.AbsListView.OnScrollListener;        import android.widget.ProgressBar;        import android.widget.TextView;                public class AlexListView extends ListView implements OnScrollListener {                    private static final String TAG = "PullToRefreshListView";                    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; // 加载中                    // 实际的padding的距离与界面上偏移距离的比例            private final static int RATIO = 3;            private LayoutInflater inflater;                    // listview的头部 用于显示刷新的箭头等            private LinearLayout headView;            private TextView tipsTextview;            private TextView lastUpdatedTextView;            private ImageView arrowImageView;            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 OnRefreshListener refreshListener;                    private boolean isRefreshable;                    public AlexListView(Context context) {                super(context);                init(context);            }                    public AlexListView(Context context, AttributeSet attrs) {                super(context, attrs);                init(context);            }                    private void init(Context context) {                // setCacheColorHint(context.getResources().getColor(Color.TRANSPARENT));                inflater = LayoutInflater.from(context);                headView = (LinearLayout) inflater.inflate(R.layout.head, 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);                        measureView(headView);                headContentHeight = headView.getMeasuredHeight();                headContentWidth = headView.getMeasuredWidth();                        headView.setPadding(0, -1 * headContentHeight, 0, 0);                headView.invalidate();                        Log.e("size", "width:" + headContentWidth + " height:"                        + headContentHeight);                        addHeaderView(headView, null, false);                setOnScrollListener(this);                // {@ TChip ZJ:逆时针旋转180度 @}                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);                // {@ TChip ZJ:顺时针旋转180度 @}                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;                isRefreshable = false;            }                    @Override            public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,                    int arg3) {                firstItemIndex = firstVisiableItem;            }                    @Override            public void onScrollStateChanged(AbsListView arg0, int arg1) {            }                    @Override            public boolean onTouchEvent(MotionEvent event) {                if (isRefreshable) {                    switch (event.getAction()) {                    case MotionEvent.ACTION_DOWN:                        if (firstItemIndex == 0 && !isRecored) {                            isRecored = true;                            // {@ TChip ZJ:记录下down事件的y位置 @}                            startY = (int) event.getY();                            Log.e(TAG, "MotionEvent.ACTION_DOWN");                        }                        break;                    case MotionEvent.ACTION_UP:                        if (state != REFRESHING && state != LOADING) {                            if (state == DONE) {                                // 什么都不做                            }                            if (state == PULL_TO_REFRESH) {                                state = DONE;                                changeHeaderViewByState();                                Log.e(TAG, "state == PULL_TO_REFRESH");                            }                            if (state == RELEASE_TO_REFRESH) {                                state = REFRESHING;                                changeHeaderViewByState();                                onRefresh();                                Log.e(TAG, "state == RELEASE_TO_REFRESH");                            }                        }                        isRecored = false;                        isBack = false;                        break;                    case MotionEvent.ACTION_MOVE:                        int tempY = (int) event.getY();                        if (!isRecored && firstItemIndex == 0) {                            Log.e(TAG, "MotionEvent.ACTION_MOVE");                            isRecored = true;                            startY = tempY;                        }                        if (state != REFRESHING && isRecored && state != LOADING) {                            // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动                            // 可以松手去刷新了                            if (state == RELEASE_TO_REFRESH) {                                setSelection(0);                                // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步                                if (((tempY - startY) / RATIO < headContentHeight)                                        && (tempY - startY) > 0) {                                    state = PULL_TO_REFRESH;                                    changeHeaderViewByState();                                    Log.e(TAG, "由松开刷新状态转变到下拉刷新状态");                                }                                // 一下子推到顶了                                else if (tempY - startY <= 0) {                                    state = DONE;                                    changeHeaderViewByState();                                    Log.e(TAG, "由松开刷新状态转变到done状态");                                }                                // 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步                                else {                                    // 不用进行特别的操作,只用更新paddingTop的值就行了                                }                            }                            // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态                            if (state == PULL_TO_REFRESH) {                                setSelection(0);                                // 下拉到可以进入RELEASE_TO_REFRESH的状态                                if ((tempY - startY) / RATIO >= headContentHeight) {                                    state = RELEASE_TO_REFRESH;                                    isBack = true;                                    changeHeaderViewByState();                                    Log.e(TAG, "由done或者下拉刷新状态转变到松开刷新");                                }                                // 上推到顶了                                else if (tempY - startY <= 0) {                                    state = DONE;                                    changeHeaderViewByState();                                    Log.e(TAG, "由Done或者下拉刷新状态转变到done状态");                                }                            }                            // done状态下                            if (state == DONE) {                                if (tempY - startY > 0) {                                    state = PULL_TO_REFRESH;                                    changeHeaderViewByState();                                }                            }                            // 更新headView的size                            if (state == PULL_TO_REFRESH) {                                headView.setPadding(0, -1 * headContentHeight                                        + (tempY - startY) / RATIO, 0, 0);                            }                            // 更新headView的paddingTop                            if (state == RELEASE_TO_REFRESH) {                                headView.setPadding(0, (tempY - startY) / RATIO                                        - headContentHeight, 0, 0);                            }                        }                        break;                    }                }                        return super.onTouchEvent(event);            }                    // 当状态改变时候,调用该方法,以更新界面            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("放开以刷新");                    Log.e(TAG, "State-->RELEASE_TO_REFRESH");                    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("下拉刷新");                    } else {                        tipsTextview.setText("下拉刷新");                    }                    Log.e(TAG, "State-->PULL_TO_REFRESH");                    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);                    Log.e(TAG, "State-->REFRESHING");                    break;                case DONE:                    headView.setPadding(0, -1 * headContentHeight, 0, 0);                    progressBar.setVisibility(View.GONE);                    arrowImageView.clearAnimation();                    arrowImageView.setImageResource(R.drawable.ic_launcher);                    tipsTextview.setText("下拉刷新");                    lastUpdatedTextView.setVisibility(View.VISIBLE);                    Log.e(TAG, "State-->DONE");                    break;                }            }                    public void setonRefreshListener(OnRefreshListener refreshListener) {                this.refreshListener = refreshListener;                isRefreshable = true;            }                    public interface OnRefreshListener {                public void onRefresh();            }                    public void onRefreshComplete() {                state = DONE;                lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());                changeHeaderViewByState();            }                    private void onRefresh() {                if (refreshListener != null) {                    refreshListener.onRefresh();                }            }                    // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height            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);            }                    public void setAdapter(BaseAdapter adapter) {                // {@ TChip ZJ:设置Header中最近更新时间 @}                lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());                super.setAdapter(adapter);            }        }  


代码下载

 

 

 

转载请注明出处:周木水的CSDN博客 http://blog.csdn.net/zhoumushui

我的GitHub:周木水的GitHub https://github.com/zhoumushui