listview实现下拉刷新

来源:互联网 发布:网络巫师泰剧中字4 编辑:程序博客网 时间:2024/04/30 06:15

重写listview,PullToRefreshListView.java

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.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ImageView;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.RelativeLayout;import android.widget.TextView;import com.zsx.youliao.R;import com.zsx.youliao.util.Mylog;import com.zsx.youliao.util.Tools; public class PullToRefreshListView extends ListView implements OnScrollListener {    private static final int TAP_TO_REFRESH = 1;    private static final int PULL_TO_REFRESH = 2;    private static final int RELEASE_TO_REFRESH = 3;    private static final int REFRESHING = 4;    private static final String TAG = "PullToRefreshListView";    private OnRefreshListener mOnRefreshListener;    /**     * Listener that will receive notifications every time the list scrolls.     */    private OnScrollListener mOnScrollListener;    private LayoutInflater mInflater;    private RelativeLayout mRefreshView;    private TextView mRefreshViewText;    private ImageView mRefreshViewImage;    private ProgressBar mRefreshViewProgress;    private TextView mRefreshViewLastUpdated;    private int mCurrentScrollState;    private int mRefreshState;    private RotateAnimation mFlipAnimation;    private RotateAnimation mReverseFlipAnimation;    private int mRefreshViewHeight;    private int mRefreshOriginalTopPadding;    private int mLastMotionY;    private boolean mBounceHack;    public PullToRefreshListView(Context context) {        super(context);        init(context);    }    public PullToRefreshListView(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init(context);    }    private void init(Context context) {    Mylog.i(TAG, "init");        // Load all of the animations we need in code rather than through XML        mFlipAnimation = 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) context.getSystemService(                Context.LAYOUT_INFLATER_SERVICE);mRefreshView = (RelativeLayout) mInflater.inflate(R.layout.pull_to_refresh_header_other, this, false);        mRefreshViewText =            (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);        mRefreshViewImage =            (ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);        mRefreshViewProgress =            (ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);        mRefreshViewLastUpdated =            (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);        mRefreshViewImage.setMinimumHeight(50);        mRefreshView.setOnClickListener(new OnClickRefreshListener());        mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();        mRefreshState = TAP_TO_REFRESH;        addHeaderView(mRefreshView);        super.setOnScrollListener(this);        measureView(mRefreshView);        mRefreshViewHeight = mRefreshView.getMeasuredHeight();        setLastUpdated(getResources().getString(R.string.string_flush_lasttime)+Tools.getTime());    }    @Override    protected void onAttachedToWindow() {        setSelection(1);    }    @Override    public void setAdapter(ListAdapter adapter) {        super.setAdapter(adapter);        setSelection(1);    }    /**     * Set the listener that will receive notifications every time the list     * scrolls.     *      * @param l The scroll listener.      */    @Override    public void setOnScrollListener(AbsListView.OnScrollListener l) {        mOnScrollListener = l;    }    /**     * Register a callback to be invoked when this list should be refreshed.     *      * @param onRefreshListener The callback to run.     */    public void setOnRefreshListener(OnRefreshListener onRefreshListener) {        mOnRefreshListener = onRefreshListener;    }    /**     * Set a text to represent when the list was last updated.      * @param lastUpdated Last updated at.     */    public void setLastUpdated(CharSequence lastUpdated) {        if (lastUpdated != null) {            mRefreshViewLastUpdated.setVisibility(View.VISIBLE);            mRefreshViewLastUpdated.setText(lastUpdated);        } else {            mRefreshViewLastUpdated.setVisibility(View.GONE);        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        final int y = (int) event.getY();        mBounceHack = false;        switch (event.getAction()) {            case MotionEvent.ACTION_UP:                if (!isVerticalScrollBarEnabled()) {                    setVerticalScrollBarEnabled(true);                }                if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {                    if ((mRefreshView.getBottom() >= mRefreshViewHeight                            || mRefreshView.getTop() >= 0)                            && mRefreshState == RELEASE_TO_REFRESH) {                        // Initiate the refresh                        mRefreshState = REFRESHING;                        prepareForRefresh();                        onRefresh();                    } else if (mRefreshView.getBottom() < mRefreshViewHeight                            || mRefreshView.getTop() <= 0) {                        // Abort refresh and scroll down below the refresh view                        resetHeader();                        setSelection(1);                    }                }                break;            case MotionEvent.ACTION_DOWN:                mLastMotionY = y;                break;            case MotionEvent.ACTION_MOVE:                applyHeaderPadding(event);                break;        }        return super.onTouchEvent(event);    }    private void applyHeaderPadding(MotionEvent ev) {        // getHistorySize has been available since API 1        int pointerCount = ev.getHistorySize();        for (int p = 0; p < pointerCount; p++) {            if (mRefreshState == RELEASE_TO_REFRESH) {                if (isVerticalFadingEdgeEnabled()) {                    setVerticalScrollBarEnabled(false);                }                int historicalY = (int) ev.getHistoricalY(p);                // Calculate the padding to apply, we divide by 1.7 to                // simulate a more resistant effect during pull.                int topPadding = (int) (((historicalY - mLastMotionY)                        - mRefreshViewHeight) / 1.7);                mRefreshView.setPadding(                        mRefreshView.getPaddingLeft(),                        topPadding,                        mRefreshView.getPaddingRight(),                        mRefreshView.getPaddingBottom());            }        }    }    /**     * Sets the header padding back to original size.     */    private void resetHeaderPadding() {        mRefreshView.setPadding(                mRefreshView.getPaddingLeft(),                mRefreshOriginalTopPadding,                mRefreshView.getPaddingRight(),                mRefreshView.getPaddingBottom());    }    /**     * Resets the header to the original state.     */    private void resetHeader() {        if (mRefreshState != TAP_TO_REFRESH) {            mRefreshState = TAP_TO_REFRESH;            resetHeaderPadding();            // Set refresh view text to the pull label            mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);            // Replace refresh drawable with arrow drawable            mRefreshViewImage.setImageResource(R.drawable.refresharrow);            // Clear the full rotation animation            mRefreshViewImage.clearAnimation();            // Hide progress bar and arrow.            mRefreshViewImage.setVisibility(View.GONE);            mRefreshViewProgress.setVisibility(View.GONE);        }    }    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);    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem,            int visibleItemCount, int totalItemCount) {        // When the refresh view is completely visible, change the text to say        // "Release to refresh..." and flip the arrow drawable.        if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL                && mRefreshState != REFRESHING) {            if (firstVisibleItem == 0) {                mRefreshViewImage.setVisibility(View.VISIBLE);                if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20                        || mRefreshView.getTop() >= 0)                        && mRefreshState != RELEASE_TO_REFRESH) {                    mRefreshViewText.setText(R.string.pull_to_refresh_release_label);                    mRefreshViewImage.clearAnimation();                    mRefreshViewImage.startAnimation(mFlipAnimation);                    mRefreshState = RELEASE_TO_REFRESH;                } else if (mRefreshView.getBottom() < mRefreshViewHeight + 20                        && mRefreshState != PULL_TO_REFRESH) {                    mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);                    if (mRefreshState != TAP_TO_REFRESH) {                        mRefreshViewImage.clearAnimation();                        mRefreshViewImage.startAnimation(mReverseFlipAnimation);                    }                    mRefreshState = PULL_TO_REFRESH;                }            } else {                mRefreshViewImage.setVisibility(View.GONE);                resetHeader();            }        } else if (mCurrentScrollState == SCROLL_STATE_FLING                && firstVisibleItem == 0                && mRefreshState != REFRESHING) {            setSelection(1);            mBounceHack = true;        } else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {            setSelection(1);        }        if (mOnScrollListener != null) {            mOnScrollListener.onScroll(view, firstVisibleItem,                    visibleItemCount, totalItemCount);        }    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        mCurrentScrollState = scrollState;        if (mCurrentScrollState == SCROLL_STATE_IDLE) {            mBounceHack = false;        }        if (mOnScrollListener != null) {            mOnScrollListener.onScrollStateChanged(view, scrollState);        }    }    public void prepareForRefresh() {        resetHeaderPadding();        mRefreshViewImage.setVisibility(View.GONE);        // We need this hack, otherwise it will keep the previous drawable.        mRefreshViewImage.setImageDrawable(null);        mRefreshViewProgress.setVisibility(View.VISIBLE);        // Set refresh view text to the refreshing label        mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);        mRefreshState = REFRESHING;    }    public void onRefresh() {        Mylog.d(TAG, "onRefresh");        if (mOnRefreshListener != null) {            mOnRefreshListener.onRefresh();        }    }    /**     * Resets the list to a normal state after a refresh.     * @param lastUpdated Last updated at.     */    public void onRefreshComplete(CharSequence lastUpdated) {        setLastUpdated(lastUpdated);        onRefreshComplete();    }    /**     * Resets the list to a normal state after a refresh.     */    public void onRefreshComplete() {                Mylog.d(TAG, "onRefreshComplete");        resetHeader();        // If refresh view is visible when loading completes, scroll down to        // the next item.        if (mRefreshView.getBottom() > 0) {            invalidateViews();            setSelection(1);        }    }    /**     * Invoked when the refresh view is clicked on. This is mainly used when     * there's only a few items in the list and it's not possible to drag the     * list.     */    private class OnClickRefreshListener implements OnClickListener {        @Override        public void onClick(View v) {            if (mRefreshState != REFRESHING) {                prepareForRefresh();                onRefresh();            }        }    }    /**     * Interface definition for a callback to be invoked when list should be     * refreshed.     */    public interface OnRefreshListener {        /**         * Called when the list should be refreshed.         * <p>         * A call to {@link PullToRefreshListView #onRefreshComplete()} is         * expected to indicate that the refresh has completed.         */        public void onRefresh();    }}

使用方法:

<包名.PullToRefreshListView        android:id="@+id/friend_list"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:scrollbars="none"        android:divider="@null"        android:dividerHeight="2dip"        android:cacheColorHint="#00000000"       />

pull_to_refresh_header_other.xml:

<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2011 Johan Nilsson <http://markupartist.com>     Licensed under the Apache License, Version 2.0 (the "License");     you may not use this file except in compliance with the License.     You may obtain a copy of the License at          http://www.apache.org/licenses/LICENSE-2.0     Unless required by applicable law or agreed to in writing, software     distributed under the License is distributed on an "AS IS" BASIS,     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.     See the License for the specific language governing permissions and     limitations under the License.--><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:paddingTop="10dip"    android:paddingBottom="15dip"    android:background="@drawable/images_bg"    android:gravity="center"        android:id="@+id/pull_to_refresh_header"    >    <ProgressBar         android:id="@+id/pull_to_refresh_progress"        android:indeterminate="true"        android:layout_width="18dip"        android:layout_height="18dip"        android:layout_marginLeft="30dip"        android:layout_marginRight="20dip"        android:layout_marginTop="20dip"        android:layout_marginBottom="10dip"        android:visibility="gone"        android:layout_centerVertical="true"        style="@style/reflushProgressStyle"        />    <ImageView        android:id="@+id/pull_to_refresh_image"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginLeft="30dip"        android:layout_marginRight="20dip"        android:visibility="gone"        android:layout_gravity="center"        android:gravity="center"        android:src="@drawable/refresharrow"        />    <TextView        android:id="@+id/pull_to_refresh_text"        android:text="@string/pull_to_refresh_pull_label"        android:textAppearance="?android:attr/textAppearanceMedium"        android:textStyle="bold"        android:paddingTop="5dip"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:gravity="center"        />    <TextView        android:id="@+id/pull_to_refresh_updated_at"        android:layout_below="@+id/pull_to_refresh_text"        android:visibility="visible"        android:textAppearance="?android:attr/textAppearanceSmall"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:gravity="center"        /></RelativeLayout>

string.xml中添加:

<string name="pull_to_refresh_pull_label">下拉刷新</string> <string name="pull_to_refresh_release_label">松开刷新</string> <string name="pull_to_refresh_refreshing_label">正在刷新...</string> <string name="string_flush_lasttime">最后更新:</string>

Tools.getTime():

public static String getTime() {SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date curDate = new Date(System.currentTimeMillis());// 获取当前时间String str = formatter.format(curDate);return str;}

说明:

refresharrow.png 是向下的箭头,
images_bg.png 是下拉刷新的背景图片
@style/reflushProgressStyle 是加载样式


在activity中需要实现OnRefreshListener接口,在onRefresh()方法中进行加载数据的操作,最好采用异步方式,在加载完后调用
onRefreshComplete()方法


需要注意的是:
下拉刷新是放到listview的头中
1、在activity加载完数据后,即适配器notifyDataSetChanged后,执行listview的setSelection(1),这样刚进入页面时下拉刷新是隐藏的;
2、在需要监听listview的长按操作或者点击操作,获取数据时记得position需要 -1
3、当数据量较少时,这时候listview在一个页面就能显示完,这时候下拉刷新将会显示出来,好的方法暂时没有想到,但通过一种取巧的方式解决了:
  在适配器的getCount方法:
         public int getCount() {
if (list != null) {
if(list.size() <6){
return 6;
}else{
return list.size() ;
}
} else {
return 0;
}


}
 因为我所写的页面listview一般显示5-6条数据,因此当数值少于这个值时,默认返回6条,这样就能让listview将页面撑满,从而达到隐藏下拉刷新的目的
 这时候在getview方法中,需要做如下操作:
               if (position <= list.size() - 1) {
convertView.setVisibility(View.VISIBLE);
                } else {
convertView.setVisibility(View.INVISIBLE);
}
 同时在listview控件中设置
        android:scrollbars="none"
        android:divider="@null"
        android:dividerHeight="2dip"
        android:cacheColorHint="#00000000"


原创粉丝点击