ListView实现上拉加载和下拉刷新

一、创建header.xml文件作为下拉头。

<?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="80dp"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/xlistview_header_content"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="16dp">

        <ProgressBar
            android:id="@+id/xlistview_header_progressbar"
            style="?android:attr/progressBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="90dp"
            android:visibility="visible" />

        <ImageView
            android:id="@+id/imageview_header_narrow"
            android:layout_width="20dp"
            android:layout_height="30dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="90dp"
            android:src="@mipmap/icon_list_view_down" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_centerVertical="true"
            android:gravity="center"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/xlistview_header_hint_textview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下拉刷新"
                android:textColor="@color/theme_color" />
        </LinearLayout>
    </RelativeLayout>

</LinearLayout>

二、自定义下拉头XListViewHeader,继承LinearLayout

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.luo.project.R;

public class XListViewHeader 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 ImageView mNarrow;
    private TextView mHintView;

    public XListViewHeader(Context context) {
        super(context);
        initView(context);
    }

    public XListViewHeader(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public void setState(int state) {
        mHintView.setVisibility(View.GONE);
        mProgressBar.setVisibility(View.GONE);
        mHintView.setVisibility(View.GONE);
        mNarrow.setVisibility(GONE);
        if (state == STATE_READY) {
            mHintView.setVisibility(View.VISIBLE);
            mNarrow.setImageResource(R.mipmap.icon_list_view_up);
            mNarrow.setVisibility(VISIBLE);
            mHintView.setText("松开刷新");
        } else if (state == STATE_LOADING) {
            mHintView.setVisibility(View.VISIBLE);
            mHintView.setText("加载中...");
            mProgressBar.setVisibility(View.VISIBLE);
        } else {
            mHintView.setVisibility(View.VISIBLE);
            mHintView.setText("下拉刷新");
            mNarrow.setImageResource(R.mipmap.icon_list_view_down);
            mNarrow.setVisibility(VISIBLE);
        }
    }

    public void setTopMargin(int height) {
        if (height < 0) return;
        LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
        lp.topMargin = height;
        mContentView.setLayoutParams(lp);
    }

    public int getTopMargin() {
        LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
        return lp.topMargin;
    }

    public void normal() {
        mNarrow.setVisibility(VISIBLE);
        mHintView.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.GONE);
    }

    public void hide() {
        LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
        lp.height = 0;
        mContentView.setLayoutParams(lp);
    }

    public void show() {
        LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
        lp.height = LayoutParams.WRAP_CONTENT;
        mContentView.setLayoutParams(lp);
    }

    private void initView(Context context) {
        mContext = context;
        LinearLayout moreView = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.header, null);
        addView(moreView);
        moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));

        mContentView = moreView.findViewById(R.id.xlistview_header_content);
        mProgressBar = moreView.findViewById(R.id.xlistview_header_progressbar);
        mHintView = (TextView) moreView.findViewById(R.id.xlistview_header_hint_textview);
        mNarrow = (ImageView) moreView.findViewById(R.id.imageview_header_narrow);
    }

}

三、创建底部上拉布局文件footer.xml

<?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="80dp"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/xlistview_footer_content"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="16dp">

        <ProgressBar
            android:id="@+id/xlistview_footer_progressbar"
            style="?android:attr/progressBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="90dp"
            android:visibility="visible" />

        <ImageView
            android:id="@+id/imageview_narrow"
            android:layout_width="20dp"
            android:layout_height="30dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="90dp"
            android:src="@mipmap/icon_list_view_up" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_centerVertical="true"
            android:gravity="center"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/xlistview_footer_hint_textview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/xlistview_footer_hint_normal"
                android:textColor="@color/theme_color" />
        </LinearLayout>
    </RelativeLayout>

</LinearLayout>

四、自定义上拉头XListViewFooter,继承LinearLayout

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.luo.project.R;

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 ImageView mNarrow;
    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.GONE);
        mProgressBar.setVisibility(View.GONE);
        mHintView.setVisibility(View.GONE);
        mNarrow.setVisibility(GONE);
        if (state == STATE_READY) {
            mHintView.setVisibility(View.VISIBLE);
            mNarrow.setImageResource(R.mipmap.icon_list_view_down);
            mNarrow.setVisibility(VISIBLE);
            mHintView.setText(R.string.xlistview_footer_hint_ready);
        } else if (state == STATE_LOADING) {
            mHintView.setVisibility(View.VISIBLE);
            mHintView.setText("加载中...");
            mProgressBar.setVisibility(View.VISIBLE);
        } else {
            mHintView.setVisibility(View.VISIBLE);
            mHintView.setText(R.string.xlistview_footer_hint_normal);
            mNarrow.setImageResource(R.mipmap.icon_list_view_up);
            mNarrow.setVisibility(VISIBLE);
        }
    }

    public void setBottomMargin(int height) {
        if (height < 0) return;
        LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
        lp.bottomMargin = height;
        mContentView.setLayoutParams(lp);
    }

    public int getBottomMargin() {
        LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
        return lp.bottomMargin;
    }

    public void normal() {
        mNarrow.setVisibility(VISIBLE);
        mHintView.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.GONE);
    }

    public void hide() {
        LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
        lp.height = 0;
        mContentView.setLayoutParams(lp);
    }

    public void show() {
        LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
        lp.height = LayoutParams.WRAP_CONTENT;
        mContentView.setLayoutParams(lp);
    }

    private void initView(Context context) {
        mContext = context;
        LinearLayout moreView = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.xlistview_footer, null);
        addView(moreView);
        moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_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);
        mNarrow = (ImageView) moreView.findViewById(R.id.imageview_narrow);
    }

}

五、自定义XListView,继承ListView

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
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.Scroller;

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

    private IXListViewListener mListViewListener;

    private XListViewHeader mHeaderView;
    private XListViewFooter mFooterView;
    private boolean mEnablePullLoad;
    private boolean mPullLoading;
    private boolean mIsFooterReady = false;

    private int mTotalItemCount;

    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

    private final static float OFFSET_RADIO = 1.8f; // support iOS like pull

    public XListView(Context context) {
        super(context);
        init(context);
    }

    public XListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public XListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        super.setOnScrollListener(this);
        mScroller = new Scroller(context, new DecelerateInterpolator());
        mFooterView = new XListViewFooter(context);
        mHeaderView = new XListViewHeader(context);
    }

    @Override
    public void setAdapter(ListAdapter adapter) {
        super.setAdapter(adapter);
        if (!mIsFooterReady) {
            mIsFooterReady = true;
            addFooterView(mFooterView);
        }
        addHeaderView(mHeaderView);
        mHeaderView.hide();
    }

    public void setPullLoadEnable(boolean enable) {
        mEnablePullLoad = enable;
        if (!mEnablePullLoad) {
            mFooterView.hide();
            mFooterView.setOnClickListener(null);
            setFooterDividersEnabled(false);
        } else {
            mPullLoading = false;
            mFooterView.show();
            mFooterView.setState(XListViewFooter.STATE_NORMAL);
            setFooterDividersEnabled(true);
            mFooterView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    startLoadMore();
                }
            });
        }
    }

    public void stopLoadMore() {
        if (mPullLoading) {
            mPullLoading = false;
            mFooterView.setState(XListViewFooter.STATE_NORMAL);
        }
    }

    private boolean mIsPullToRefresh = false;

    public void stopRefresh() {
        if (mIsPullToRefresh) {
            mIsPullToRefresh = false;
            mHeaderView.setState(XListViewFooter.STATE_NORMAL);
            mHeaderView.setTopMargin(0);
            mHeaderView.hide();
        }
    }

    private void invokeOnScrolling() {
        if (mScrollListener instanceof OnXScrollListener) {
            OnXScrollListener l = (OnXScrollListener) mScrollListener;
            l.onXScrolling(this);
        }
    }

    private void updateFooterHeight(float delta) {
        int height = mFooterView.getBottomMargin() + (int) delta;
        if (mEnablePullLoad && !mPullLoading) {
            if (height > PULL_LOAD_MORE_DELTA) {
                mFooterView.setState(XListViewFooter.STATE_READY);
            } else {
                mFooterView.setState(XListViewFooter.STATE_NORMAL);
            }
        }
        mFooterView.setBottomMargin(height);
    }

    private void updateHeaderHeight(float delta) {
        int height = mHeaderView.getTopMargin() + (int) delta;
            mHeaderView.show();
            if (height > PULL_LOAD_MORE_DELTA) {
                mHeaderView.setState(XListViewFooter.STATE_READY);
                mIsPullToRefresh = true;
            } else {
                mHeaderView.setState(XListViewFooter.STATE_NORMAL);
                mIsPullToRefresh = false;
            }
        mHeaderView.setTopMargin(height);
    }

    private void resetFooterHeight() {
        int bottomMargin = mFooterView.getBottomMargin();
        if (bottomMargin > 0) {
            mScrollBack = SCROLLBACK_FOOTER;
            mScroller.startScroll(0, bottomMargin, 0, -bottomMargin, SCROLL_DURATION);
            invalidate();
        }
    }

    private void resetHeaderHeight() {
        int topMargin = mHeaderView.getTopMargin();
        if (topMargin > 0) {
            mScrollBack = SCROLLBACK_FOOTER;
            mScroller.startScroll(0, -topMargin, 0, topMargin, SCROLL_DURATION);
            invalidate();
        }
    }

    private void startLoadMore() {
        mPullLoading = true;
        mFooterView.setState(XListViewFooter.STATE_LOADING);
        if (mListViewListener != null) {
            mListViewListener.onLoadMore();
        }
    }

    private void startRefresh() {
        mIsPullToRefresh = true;
        mHeaderView.setState(XListViewFooter.STATE_LOADING);
        if (mListViewListener != null) {
            mListViewListener.onRefresh();
        }
    }


    @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();

                if (getLastVisiblePosition() == mTotalItemCount - 1 && (mFooterView.getBottomMargin() > 0 || deltaY < 0)) {
                    updateFooterHeight(-deltaY / OFFSET_RADIO);
                }

                if (getFirstVisiblePosition() == 0 && (mHeaderView.getTopMargin() > 0 || deltaY > 0)) {
                    updateHeaderHeight(deltaY / OFFSET_RADIO);
                }

                break;
            default:
                mLastY = -1;
                if (getLastVisiblePosition() == mTotalItemCount - 1) {
                    if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA && !mPullLoading) {
                        startLoadMore();
                    }
                    resetFooterHeight();
                }

                if (getFirstVisiblePosition() == 0) {
                    if (mHeaderView.getTopMargin() > PULL_LOAD_MORE_DELTA && mIsPullToRefresh) {
                        mHeaderView.setTopMargin(0);
                        startRefresh();
                    }else {
                        mHeaderView.setTopMargin(0);
                        mHeaderView.hide();
                    }
                    resetHeaderHeight();
                }else {
                    mHeaderView.setTopMargin(0);
                    mHeaderView.hide();
                }

                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) {
        mTotalItemCount = totalItemCount;
        if (mScrollListener != null) {
            mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
        }
    }

    public void setXListViewListener(IXListViewListener l) {
        mListViewListener = l;
    }

    public interface OnXScrollListener extends OnScrollListener {
        void onXScrolling(View view);
    }

    public interface IXListViewListener {
        void onLoadMore();
        void onRefresh();
    }
}

六、在Activity里面使用

public class XListViewActivity extends Activity implements XListView.IXListViewListener {
    private XListView mListView;
    private ListAdapter mListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }

    private void init() {
        findView();
        setAdapter();
    }

    private void findView() {
        mListView = (XListView) mRootView.findViewById(R.id.xlistview);
    }

    private void setAdapter() {
        mListView.setXListViewListener(this);
        mListAdapter = new ListAdapter(getActivity());
        mListView.setAdapter(mListAdapter);
        mListView.setPullLoadEnable(false);
    }

    @Override
    public void onLoadMore() {
        Log.e("加载更多");
        loadDateList();
    }

    @Override
    public void onRefresh() {
         mListAdapter.clear();
         mListAdapter.addAll(list);
    }


    private void onFiish(){
        mListView.setPullLoadEnable(true);
        mListView.stopLoadMore();
        mListAdapter.addAll(list);
        mListView.stopLoadMore();
    }
}
发布了27 篇原创文章 · 获赞 32 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/luoyingxing/article/details/52400672