自定义XlistView(上拉加载,下拉刷新)控件

来源:互联网 发布:网络兼职诈骗专题分析 编辑:程序博客网 时间:2024/06/08 12:30

之前在博客里边讲了Android Studio自带的 下拉刷新控件,今天就把之前写过的自定义XlistView整理了一下,然后把代码贴出来。

Demo传送门 : http://download.csdn.net/detail/as_jon/9652906

首先肯定是先定义一个xml文件,代码如下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center">    <com.example.administrator.xlistview.PullToRefreshView        android:id="@+id/main_pull_refresh_view_two"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:orientation="vertical" >        <ListView            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:id="@+id/listview_test"            >        </ListView>    </com.example.administrator.xlistview.PullToRefreshView></LinearLayout>

接着就是在你的主界面里边进行整合,代码如下:

package com.example.administrator.stock_sell_storage_app;import android.os.Bundle;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ListView;import com.example.administrator.dapter.DetailAdapter;import com.example.administrator.xlistview.PullToRefreshView;import com.lidroid.xutils.ViewUtils;import com.lidroid.xutils.view.annotation.ViewInject;public class DetailFragment extends Fragment implements PullToRefreshView.OnHeaderRefreshListener, PullToRefreshView.OnFooterRefreshListener {    private View view;    @ViewInject(R.id.listview_test)ListView listview_test;    @ViewInject(R.id.main_pull_refresh_view_two)PullToRefreshView main_pull_refresh_view_two;    DetailAdapter detailAdapter;    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        view = inflater.inflate(R.layout.detai_fragment, container, false);        ViewUtils.inject(this,view); //注入view和事件        Instantiation();        return view;    }    public void Instantiation(){        main_pull_refresh_view_two.setOnHeaderRefreshListener(this);        main_pull_refresh_view_two.setOnFooterRefreshListener(this);        detailAdapter = new DetailAdapter(getActivity());        listview_test.setAdapter(detailAdapter);    }    //上拉加载    @Override    public void onFooterRefresh(PullToRefreshView view) {        main_pull_refresh_view_two.postDelayed(new Runnable() {            //线程            @Override            public void run() {                main_pull_refresh_view_two.onFooterRefreshComplete();                //需要刷新的内容可以写在这里,比如网络请求            }        },1000);    }    //下拉刷新    @Override    public void onHeaderRefresh(PullToRefreshView view) {        main_pull_refresh_view_two.postDelayed(new Runnable() {            //线程            @Override            public void run() {                main_pull_refresh_view_two.onHeaderRefreshComplete();                //需要刷新的内容可以写在这里,比如网络请求            }        },1000);    }}

大家应该发现了在布局文件中的那个自定义控件,其实就是下边的这个东东……

这里写图片描述


下面就把这几个类贴出来,PullToRefreshView类

package com.example.administrator.xlistview;import android.content.Context;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.AdapterView;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ProgressBar;import android.widget.ScrollView;import android.widget.TextView;import com.example.administrator.stock_sell_storage_app.R;/** * Created by Administrator on 2016-04-26. */public class PullToRefreshView extends LinearLayout {    private static final String TAG = "PullToRefreshView";    // refresh states    private static final int PULL_TO_REFRESH = 2;    private static final int RELEASE_TO_REFRESH = 3;    private static final int REFRESHING = 4;    // pull state    private 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();    }    private void 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.from(getContext());        // header view 在此添加,保证是第一个添加到linearlayout的最上端        addHeaderView();    }    private void addHeaderView() {        // header view        mHeaderView = 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 layout        measureView(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 view        mFooterView = 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 layout        measureView(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);    }    @Override    protected void onFinishInflate() {        super.onFinishInflate();        // footer view 在此添加保证添加到linearlayout中的最后        addFooterView();        initContentAdapterView();    }    /**     * init AdapterView like ListView,GridView and so on;or init ScrollView     *     * @description hylin 2012-7-30下午8:48:12     */    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 later                mScrollView = (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);    }    @Override    public 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自己来处理)     */    @Override    public 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和GridView        if (mAdapterView != null) {            // 子view(ListView or GridView)滑动到最顶端            if (deltaY > 0) {                View child = mAdapterView.getChildAt(0);                if (child == null) {                    // 如果mAdapterView中没有数据,不拦截                    return false;                }                if (mAdapterView.getFirstVisiblePosition() == 0                        && child.getTop() == 0) {                    mPullState = PULL_DOWN_STATE;                    return true;                }                int top = child.getTop();                int padding = mAdapterView.getPaddingTop();                if (mAdapterView.getFirstVisiblePosition() == 0                        && Math.abs(top - padding) <= 8) {  //这里之前用3可以判断,但现在不行,还没找到原因                    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()                        && mAdapterView.getLastVisiblePosition() == mAdapterView                        .getCount() - 1) {                    mPullState = PULL_UP_STATE;                    return true;                }            }        }        // 对于ScrollView        if (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;        } else if (newTopMargin < 0 && newTopMargin > -mHeaderViewHeight) {// 拖动时没有释放            mHeaderImageView.clearAnimation();            mHeaderImageView.startAnimation(mFlipAnimation);            // mHeaderImageView.            mHeaderTextView.setText(R.string.pull_to_refresh_pull_label);            mHeaderState = PULL_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;        } else if (Math.abs(newTopMargin) < (mHeaderViewHeight + mFooterViewHeight)) {            mFooterImageView.clearAnimation();            mFooterImageView.startAnimation(mFlipAnimation);            mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label);            mFooterState = PULL_TO_REFRESH;        }    }    /**     * 修改Header view top margin的值     *     * @description     * @param deltaY     * @return hylin 2012-7-31下午1:14:31     */    private int changingHeaderViewTopMargin(int deltaY) {        LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();        float newTopMargin = params.topMargin + deltaY * 0.3f;        //这里对上拉做一下限制,因为当前上拉后然后不释放手指直接下拉,会把下拉刷新给触发了,感谢网友yufengzungzhe的指出        //表示如果是在上拉后一段距离,然后直接下拉        if(deltaY>0&&mPullState == PULL_UP_STATE&&Math.abs(params.topMargin) <= mHeaderViewHeight){            return params.topMargin;        }        //同样地,对下拉做一下限制,避免出现跟上拉操作时一样的bug        if(deltaY<0&&mPullState == PULL_DOWN_STATE&&Math.abs(params.topMargin)>=mHeaderViewHeight){            return params.topMargin;        }        params.topMargin = (int) newTopMargin;        mHeaderView.setLayoutParams(params);        invalidate();        return params.topMargin;    }    /**     * header refreshing     *     * @description hylin 2012-7-31上午9:10:12     */    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     *     * @description hylin 2012-7-31上午9:09:59     */    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时,说明完全隐藏了     *            hylin 2012-7-31上午11:24:06     */    private void setHeaderTopMargin(int topMargin) {        LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();        params.topMargin = topMargin;        mHeaderView.setLayoutParams(params);        invalidate();    }    /**     * header view 完成更新后恢复初始状态     *     * @description hylin 2012-7-31上午11:54:23     */    public void onHeaderRefreshComplete() {        setHeaderTopMargin(-mHeaderViewHeight);        mHeaderImageView.setVisibility(View.VISIBLE);        mHeaderImageView.setImageResource(R.mipmap.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.mipmap.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     * @return hylin 2012-7-31上午11:22:50     */    private int getHeaderTopMargin() {        LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();        return params.topMargin;    }//  /**//   * lock//   *//   * @description hylin 2012-7-27下午6:52:25//   *///  private void lock() {//      mLock = true;//  }////  /**//   * unlock//   *//   * @description hylin 2012-7-27下午6:53:18//   *///  private void unlock() {//      mLock = false;//  }    /**     * set headerRefreshListener     *     * @description     * @param headerRefreshListener     *            hylin 2012-7-31上午11:43:58     */    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);    }}

XListView类:

package com.example.administrator.xlistview;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewTreeObserver.OnGlobalLayoutListener;import android.view.animation.DecelerateInterpolator;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.RelativeLayout;import android.widget.Scroller;import android.widget.TextView;import com.example.administrator.stock_sell_storage_app.R;/** * @file XListView.java * @package me.maxwin.view * @create Mar 18, 2012 6:28:41 PM * @author Maxwin * @description An ListView support (a) Pull down to refresh, (b) Pull up to load more. *      Implement IXListViewListener, and see stopRefresh() / stopLoadMore(). */public class XListView extends ListView implements OnScrollListener {    private float mLastY = -1; // save event y    private Scroller mScroller; // used for scroll back    private OnScrollListener mScrollListener; // user's scroll listener    // the interface to trigger refresh and load more.    private IXListViewListener mListViewListener;    // -- header view    private XListViewHeader mHeaderView;    // header view content, use it to calculate the Header's height. And hide it    // when disable pull refresh.    private RelativeLayout mHeaderViewContent;    private TextView mHeaderTimeView;    private int mHeaderViewHeight; // header view's height    private boolean mEnablePullRefresh = true;    private boolean mPullRefreshing = false; // is refreashing.    // -- footer view    private XListViewFooter mFooterView;    private boolean mEnablePullLoad;    private boolean mPullLoading;    private boolean mIsFooterReady = false;    // total list items, used to detect is at the bottom of listview.    private int mTotalItemCount;    // for mScroller, scroll back from header or footer.    private int mScrollBack;    private final static int SCROLLBACK_HEADER = 0;    private final static int SCROLLBACK_FOOTER = 1;    private final static int SCROLL_DURATION = 400; // scroll back duration    private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px    // at bottom, trigger    // load more.    private final static float OFFSET_RADIO = 1.8f; // support iOS like pull    // feature.    /**     * @param context     */    public XListView(Context context) {        super(context);        initWithContext(context);    }    public XListView(Context context, AttributeSet attrs) {        super(context, attrs);        initWithContext(context);    }    public XListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        initWithContext(context);    }    private void initWithContext(Context context) {        mScroller = new Scroller(context, new DecelerateInterpolator());        // XListView need the scroll event, and it will dispatch the event to        // user's listener (as a proxy).        super.setOnScrollListener(this);        // init header view        mHeaderView = new XListViewHeader(context);        mHeaderViewContent = (RelativeLayout) mHeaderView                .findViewById(R.id.xlistview_header_content);        mHeaderTimeView = (TextView) mHeaderView                .findViewById(R.id.xlistview_header_time);        addHeaderView(mHeaderView);        // init footer view        mFooterView = new XListViewFooter(context);        // init header height        mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(                new OnGlobalLayoutListener() {                    @SuppressWarnings("deprecation")                    @Override                    public void onGlobalLayout() {                        mHeaderViewHeight = mHeaderViewContent.getHeight();                        getViewTreeObserver()                                .removeGlobalOnLayoutListener(this);                    }                });    }    @Override    public void setAdapter(ListAdapter adapter) {        // make sure XListViewFooter is the last footer view, and only add once.        if (mIsFooterReady == false) {            mIsFooterReady = true;            addFooterView(mFooterView);        }        super.setAdapter(adapter);    }    /**     * enable or disable pull down refresh feature.     *     * @param enable     */    public void setPullRefreshEnable(boolean enable) {        mEnablePullRefresh = enable;        if (!mEnablePullRefresh) { // disable, hide the content            mHeaderViewContent.setVisibility(View.INVISIBLE);        } else {            mHeaderViewContent.setVisibility(View.VISIBLE);        }    }    /**     * enable or disable pull up load more feature.     *     * @param enable     */    public void setPullLoadEnable(boolean enable) {        mEnablePullLoad = enable;        if (!mEnablePullLoad) {            mFooterView.hide();            mFooterView.setOnClickListener(null);        } else {            mPullLoading = false;            mFooterView.show();            mFooterView.setState(XListViewFooter.STATE_NORMAL);            // both "pull up" and "click" will invoke load more.            mFooterView.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View v) {                    startLoadMore();                }            });        }    }    /**     * stop refresh, reset header view.     */    public void stopRefresh() {        if (mPullRefreshing == true) {            mPullRefreshing = false;            resetHeaderHeight();        }    }    /**     * stop load more, reset footer view.     */    public void stopLoadMore() {        if (mPullLoading == true) {            mPullLoading = false;            mFooterView.setState(XListViewFooter.STATE_NORMAL);        }    }    /**     * set last refresh time     *     * @param time     */    public void setRefreshTime(String time) {        mHeaderTimeView.setText(time);    }    private void invokeOnScrolling() {        if (mScrollListener instanceof OnXScrollListener) {            OnXScrollListener l = (OnXScrollListener) mScrollListener;            l.onXScrolling(this);        }    }    private void updateHeaderHeight(float delta) {        mHeaderView.setVisiableHeight((int) delta                + mHeaderView.getVisiableHeight());        if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态,更新箭头            if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {                mHeaderView.setState(XListViewHeader.STATE_READY);            } else {                mHeaderView.setState(XListViewHeader.STATE_NORMAL);            }        }        setSelection(0); // scroll to top each time    }    /**     * reset header view's height.     */    private void resetHeaderHeight() {        int height = mHeaderView.getVisiableHeight();        if (height == 0) // not visible.            return;        // refreshing and header isn't shown fully. do nothing.        if (mPullRefreshing && height <= mHeaderViewHeight) {            return;        }        int finalHeight = 0; // default: scroll back to dismiss header.        // is refreshing, just scroll back to show all the header.        if (mPullRefreshing && height > mHeaderViewHeight) {            finalHeight = mHeaderViewHeight;        }        mScrollBack = SCROLLBACK_HEADER;        mScroller.startScroll(0, height, 0, finalHeight - height,                SCROLL_DURATION);        // trigger computeScroll        invalidate();    }    private void updateFooterHeight(float delta) {        int height = mFooterView.getBottomMargin() + (int) delta;        if (mEnablePullLoad && !mPullLoading) {            if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load                // more.                mFooterView.setState(XListViewFooter.STATE_READY);            } else {                mFooterView.setState(XListViewFooter.STATE_NORMAL);            }        }        mFooterView.setBottomMargin(height);        // setSelection(mTotalItemCount - 1); // scroll to bottom    }    private void resetFooterHeight() {        int bottomMargin = mFooterView.getBottomMargin();        if (bottomMargin > 0) {            mScrollBack = SCROLLBACK_FOOTER;            mScroller.startScroll(0, bottomMargin, 0, -bottomMargin,                    SCROLL_DURATION);            invalidate();        }    }    private void startLoadMore() {        mPullLoading = true;        mFooterView.setState(XListViewFooter.STATE_LOADING);        if (mListViewListener != null) {            mListViewListener.onLoadMore();        }    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        if (mLastY == -1) {            mLastY = ev.getRawY();        }        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                mLastY = ev.getRawY();                break;            case MotionEvent.ACTION_MOVE:                final float deltaY = ev.getRawY() - mLastY;                mLastY = ev.getRawY();                System.out.println("数据监测:" + getFirstVisiblePosition() + "---->"                        + getLastVisiblePosition());                if (getFirstVisiblePosition() == 0                        && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {                    // the first item is showing, header has shown or pull down.                    updateHeaderHeight(deltaY / OFFSET_RADIO);                    invokeOnScrolling();                } else if (getLastVisiblePosition() == mTotalItemCount - 1                        && (mFooterView.getBottomMargin() > 0 || deltaY < 0)) {                    // last item, already pulled up or want to pull up.                    updateFooterHeight(-deltaY / OFFSET_RADIO);                }                break;            default:                mLastY = -1; // reset                if (getFirstVisiblePosition() == 0) {                    // invoke refresh                    if (mEnablePullRefresh                            && mHeaderView.getVisiableHeight() > mHeaderViewHeight) {                        mPullRefreshing = true;                        mHeaderView.setState(XListViewHeader.STATE_REFRESHING);                        if (mListViewListener != null) {                            mListViewListener.onRefresh();                        }                    }                    resetHeaderHeight();                }                if (getLastVisiblePosition() == mTotalItemCount - 1) {                    // invoke load more.                    if (mEnablePullLoad                            && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA) {                        startLoadMore();                    }                    resetFooterHeight();                }                break;        }        return super.onTouchEvent(ev);    }    @Override    public void computeScroll() {        if (mScroller.computeScrollOffset()) {            if (mScrollBack == SCROLLBACK_HEADER) {                mHeaderView.setVisiableHeight(mScroller.getCurrY());            } else {                mFooterView.setBottomMargin(mScroller.getCurrY());            }            postInvalidate();            invokeOnScrolling();        }        super.computeScroll();    }    @Override    public void setOnScrollListener(OnScrollListener l) {        mScrollListener = l;    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        if (mScrollListener != null) {            mScrollListener.onScrollStateChanged(view, scrollState);        }    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem,                         int visibleItemCount, int totalItemCount) {        // send to user's listener        mTotalItemCount = totalItemCount;        if (mScrollListener != null) {            mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,                    totalItemCount);        }    }    public void setXListViewListener(IXListViewListener l) {        mListViewListener = l;    }    /**     * you can listen ListView.OnScrollListener or this one. it will invoke     * onXScrolling when header/footer scroll back.     */    public interface OnXScrollListener extends OnScrollListener {        public void onXScrolling(View view);    }    /**     * implements this interface to get refresh/load more event.     */    public interface IXListViewListener {        public void onRefresh();        public void onLoadMore();    }}

XListViewFooter类:

package com.example.administrator.xlistview;import android.content.Context;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.widget.LinearLayout;import android.widget.TextView;import com.example.administrator.stock_sell_storage_app.R;/** * Created by Administrator on 2016-04-26. *//** * @file XFooterView.java * @create Mar 31, 2012 9:33:43 PM * @author Maxwin * @description XListView's footer */public class XListViewFooter extends LinearLayout {    public final static int STATE_NORMAL = 0;    public final static int STATE_READY = 1;    public final static int STATE_LOADING = 2;    private Context mContext;    private View mContentView;    private View mProgressBar;    private TextView mHintView;    public XListViewFooter(Context context) {        super(context);        initView(context);    }    public XListViewFooter(Context context, AttributeSet attrs) {        super(context, attrs);        initView(context);    }    public void setState(int state) {        mHintView.setVisibility(View.INVISIBLE);        mProgressBar.setVisibility(View.INVISIBLE);        mHintView.setVisibility(View.INVISIBLE);        if (state == STATE_READY) {            mHintView.setVisibility(View.VISIBLE);            mHintView.setText(R.string.xlistview_footer_hint_ready);        } else if (state == STATE_LOADING) {            mProgressBar.setVisibility(View.VISIBLE);        } else {            mHintView.setVisibility(View.VISIBLE);            mHintView.setText(R.string.xlistview_footer_hint_normal);        }    }    public void setBottomMargin(int height) {        if (height < 0) return ;        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();        lp.bottomMargin = height;        mContentView.setLayoutParams(lp);    }    public int getBottomMargin() {        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();        return lp.bottomMargin;    }    /**     * normal status     */    public void normal() {        mHintView.setVisibility(View.VISIBLE);        mProgressBar.setVisibility(View.GONE);    }    /**     * loading status     */    public void loading() {        mHintView.setVisibility(View.GONE);        mProgressBar.setVisibility(View.VISIBLE);    }    /**     * hide footer when disable pull load more     */    public void hide() {        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();        lp.height = 0;        mContentView.setLayoutParams(lp);    }    /**     * show footer     */    public void show() {        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();        lp.height = LayoutParams.WRAP_CONTENT;        mContentView.setLayoutParams(lp);    }    @SuppressWarnings("deprecation")    private void initView(Context context) {        mContext = context;        LinearLayout moreView = (LinearLayout)LayoutInflater.from(mContext).inflate(R.layout.xlistview_footer, null);        addView(moreView);        moreView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));        mContentView = moreView.findViewById(R.id.xlistview_footer_content);        mProgressBar = moreView.findViewById(R.id.xlistview_footer_progressbar);        mHintView = (TextView)moreView.findViewById(R.id.xlistview_footer_hint_textview);    }}

XListViewHeader类:

package com.example.administrator.xlistview;import android.content.Context;import android.util.AttributeSet;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.animation.Animation;import android.view.animation.RotateAnimation;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ProgressBar;import android.widget.TextView;import com.example.administrator.stock_sell_storage_app.R;public class XListViewHeader extends LinearLayout {    private LinearLayout mContainer;    private ImageView mArrowImageView;    private ProgressBar mProgressBar;    private TextView mHintTextView;    private int mState = STATE_NORMAL;    private Animation mRotateUpAnim;    private Animation mRotateDownAnim;    private final int ROTATE_ANIM_DURATION = 180;    public final static int STATE_NORMAL = 0;    public final static int STATE_READY = 1;    public final static int STATE_REFRESHING = 2;    public XListViewHeader(Context context) {        super(context);        initView(context);    }    /**     * @param context     * @param attrs     */    public XListViewHeader(Context context, AttributeSet attrs) {        super(context, attrs);        initView(context);    }    @SuppressWarnings("deprecation")    private void initView(Context context) {        // 初始情况,设置下拉刷新view高度为0        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(                LayoutParams.FILL_PARENT, 0);        mContainer = (LinearLayout) LayoutInflater.from(context).inflate(                R.layout.xlistview_header, null);        addView(mContainer, lp);        setGravity(Gravity.BOTTOM);        mArrowImageView = (ImageView)findViewById(R.id.xlistview_header_arrow);        mHintTextView = (TextView)findViewById(R.id.xlistview_header_hint_textview);        mProgressBar = (ProgressBar)findViewById(R.id.xlistview_header_progressbar);        mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,                0.5f);        mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);        mRotateUpAnim.setFillAfter(true);        mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,                0.5f);        mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);        mRotateDownAnim.setFillAfter(true);    }    public void setState(int state) {        if (state == mState) return ;        if (state == STATE_REFRESHING) {    // 显示进度            mArrowImageView.clearAnimation();            mArrowImageView.setVisibility(View.INVISIBLE);            mProgressBar.setVisibility(View.VISIBLE);        } else {    // 显示箭头图片            mArrowImageView.setVisibility(View.VISIBLE);            mProgressBar.setVisibility(View.INVISIBLE);        }        switch(state){            case STATE_NORMAL:                if (mState == STATE_READY) {                    mArrowImageView.startAnimation(mRotateDownAnim);                }                if (mState == STATE_REFRESHING) {                    mArrowImageView.clearAnimation();                }                mHintTextView.setText(R.string.xlistview_header_hint_normal);                break;            case STATE_READY:                if (mState != STATE_READY) {                    mArrowImageView.clearAnimation();                    mArrowImageView.startAnimation(mRotateUpAnim);                    mHintTextView.setText(R.string.xlistview_header_hint_ready);                }                break;            case STATE_REFRESHING:                mHintTextView.setText(R.string.xlistview_header_hint_loading);                break;            default:        }        mState = state;    }    public void setVisiableHeight(int height) {        if (height < 0)            height = 0;        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer                .getLayoutParams();        lp.height = height;        mContainer.setLayoutParams(lp);    }    public int getVisiableHeight() {        return mContainer.getHeight();    }}

OK!大家可以根据步骤把这几个类放在一个文件目录下。接下来还有一些相关的xml文件,我也一并贴在下边了。

xml(一) refresh_footer

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/pull_to_refresh_header"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:background="@android:color/white"    android:gravity="center"    android:paddingBottom="10dip"    android:paddingTop="10dip" >    <ProgressBar        android:id="@+id/pull_to_load_progress"        style="?android:attr/progressBarStyleSmall"        android:layout_width="30dp"        android:layout_height="30dp"        android:layout_marginLeft="90dp"        android:layout_centerVertical="true"        android:visibility="gone" />    <ImageView        android:id="@+id/pull_to_load_image"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:layout_marginLeft="95dp"        android:gravity="center"        android:src="@mipmap/ic_pulltorefresh_arrow_up"        android:visibility="visible" />    <TextView        android:id="@+id/pull_to_load_text"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:gravity="center"        android:textColor="#000000"        android:text="@string/pull_to_refresh_footer_pull_label"        android:textAppearance="?android:attr/textAppearanceMedium"        android:textStyle="bold" /></RelativeLayout>

xml(二) refresh_header

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/pull_to_refresh_header"    android:background="@android:color/white"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:gravity="center"    android:paddingBottom="15dip"    android:paddingTop="10dip" >    <ProgressBar        android:id="@+id/pull_to_refresh_progress"        style="?android:attr/progressBarStyleSmall"        android:layout_width="30dp"        android:layout_height="30dp"        android:layout_marginLeft="90dp"        android:layout_centerVertical="true"        android:visibility="invisible" />    <ImageView        android:id="@+id/pull_to_refresh_image"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:layout_marginLeft="95dp"        android:layout_marginTop="5dp"        android:gravity="center"        android:src="@mipmap/ic_pulltorefresh_arrow"        android:visibility="visible" />    <TextView        android:id="@+id/pull_to_refresh_text"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:layout_marginTop="5dp"        android:gravity="center"        android:textColor="#000000"        android:text="@string/pull_to_refresh_pull_label"        android:textAppearance="?android:attr/textAppearanceMedium"        android:textStyle="bold" />    <TextView        android:id="@+id/pull_to_refresh_updated_at"        android:layout_width="fill_parent"        android:layout_height="30dip"        android:layout_below="@+id/pull_to_refresh_text"        android:text="更新于:刚刚"        android:layout_gravity="center"        android:gravity="center"        android:textAppearance="?android:attr/textAppearanceSmall"        android:visibility="gone" /></RelativeLayout>

xml(三) xlistview_footer

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content" >    <RelativeLayout        android:id="@+id/xlistview_footer_content"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:padding="10dp" >        <ProgressBar            android:id="@+id/xlistview_footer_progressbar"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:visibility="invisible" />        <TextView            android:id="@+id/xlistview_footer_hint_textview"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:text="@string/xlistview_footer_hint_normal" />    </RelativeLayout></LinearLayout>

xml(四) xlistview_header

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:gravity="bottom" >    <RelativeLayout        android:id="@+id/xlistview_header_content"        android:layout_width="fill_parent"        android:layout_height="60dp" >        <LinearLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:gravity="center"            android:orientation="vertical" android:id="@+id/xlistview_header_text">            <TextView                android:id="@+id/xlistview_header_hint_textview"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="@string/xlistview_header_hint_normal" />            <LinearLayout                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_marginTop="3dp" >                <TextView                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:text="@string/xlistview_header_last_time"                    android:textSize="12sp" />                <TextView                    android:id="@+id/xlistview_header_time"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:textSize="12sp" />            </LinearLayout>        </LinearLayout>        <ImageView            android:id="@+id/xlistview_header_arrow"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignLeft="@id/xlistview_header_text"            android:layout_centerVertical="true"            android:layout_marginLeft="-35dp"            android:src="@mipmap/xlistview_arrow" />        <ProgressBar            android:id="@+id/xlistview_header_progressbar"            android:layout_width="30dp"            android:layout_height="30dp"            android:layout_alignLeft="@id/xlistview_header_text"            android:layout_centerVertical="true"            android:layout_marginLeft="-40dp"            android:visibility="invisible" />    </RelativeLayout></LinearLayout>

好的,到了这里的话,基本上xml文件都来了,最后,再把一些资源文件也贴出来,包括里边用到的一些图片

    <!--XlistView-->    <string name="pull_to_refresh_refreshing_label">刷新\u2026</string>    <string name="pull_to_refresh_footer_release_label">松开后加载</string>    <string name="pull_to_refresh_footer_refreshing_label">加载中\u2026</string>    <string name="pull_to_refresh_release_label">松开后刷新</string>    <string name="pull_to_refresh_footer_pull_label">上拉加载更多</string>    <string name="pull_to_refresh_pull_label">下拉刷新</string>    <string name="xlistview_header_hint_normal">下拉刷新</string>    <string name="xlistview_header_hint_ready">松开刷新数据</string>    <string name="xlistview_header_hint_loading">正在加载...</string>    <string name="xlistview_header_last_time">上次更新时间:</string>    <string name="xlistview_footer_hint_normal">查看更多</string>    <string name="xlistview_footer_hint_ready">松开载入更多</string>

这里写图片描述

这里写图片描述

这里写图片描述


图片以及一些资源文件都贴上去了,到此处为止一个自定义的XlistView控件就实现了。把效果贴出来给他家看看,虽然是有点丑(- -)。

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述


还是觉得有点丑…… 不过都是自定义的,大家可以按照自己的喜好来设计。

2 0
原创粉丝点击