自定义控件之上拉刷新

自定义控件所需要的布局文件:xlistview_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="wrap_content" >

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

        <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="查看更多" />
    </RelativeLayout>

</LinearLayout>

自定义控件:XListView.java

/* 
 * @(#)XListView.java
 *
 * Copyright 2015, .....
 */
package com.example.test_my_x_list_view.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
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.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Scroller;
import android.widget.TextView;

import com.example.test_my_x_list_view.R;

/**
 * XListView:上拉刷新
 * 
 * <p>
 * <b>History:</b>
 * <table border="1">
 * <tr>
 * <th>Date</th>
 * <th>Operator</th>
 * <th>Memo</th>
 * </tr>
 * <tr>
 * <td>2015-5-13</td>
 * <td>Zjc</td>
 * <td>Create</td>
 * </tr>
 * </table>
 * 
 * @author Zjc
 * 
 * @version 1.0.0
 * @since 1.0.0
 */
public class XListView extends ListView implements OnScrollListener {

    private float mLastY = -1;
    private Scroller mScroller;
    private OnScrollListener mScrollListener;
    private IXListViewListener mListViewListener;
    public 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;
    private final static int PULL_LOAD_MORE_DELTA = 50;
    private final static float OFFSET_RADIO = 1.8f;

    /**
     * 默认构造方法
     * 
     * @param context
     * @param attrs
     */
    public XListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initWithContext(context);
    }

    /**
     * 默认构造方法
     * 
     * @param context
     * @param attrs
     * @param defStyle
     */
    public XListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initWithContext(context);
    }

    /**
     * 默认构造方法
     * 
     * @param context
     */
    public XListView(Context context) {
        super(context);
        initWithContext(context);
    }

    /**
     * 根据上下文进行初始化
     * 
     * @param context
     */
    private void initWithContext(Context context) {
        mScroller = new Scroller(context, new DecelerateInterpolator());
        super.setOnScrollListener(this);
        mFooterView = new XListViewFooter(context);
    }

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

    /**
     * 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();
                }
            });
        }
    }

    private void startLoadMore() {
        mPullLoading = true;
        // 设置底部状态
        mFooterView.setState(XListViewFooter.STATE_LOADING);
        if (mListViewListener != null) {
            mListViewListener.onLoadMore();
        }
    }

    /**
     * stop load more, reset footer view.
     */
    public void stopLoadMore() {
        if (mPullLoading == true) {
            mPullLoading = false;
            mFooterView.setState(XListViewFooter.STATE_NORMAL);
        }
    }

    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 invokeOnScrolling() {
        if (mScrollListener instanceof OnXScrollListener) {
            OnXScrollListener l = (OnXScrollListener) mScrollListener;
            l.onXScrolling(this);
        }
    }

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

    @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);
            }
            break;
        default:
            mLastY = -1; // reset
            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) {
                mFooterView.setBottomMargin(mScroller.getCurrY());
            }
            postInvalidate();
            invokeOnScrolling();
        }
        super.computeScroll();
    }

    @Override
    public void setOnScrollListener(OnScrollListener l) {
        mScrollListener = l;
    }

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

    public interface IXListViewListener {
        public void onLoadMore();
    }

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

    /*
     * (non-Javadoc)
     * 
     * @see
     * android.widget.AbsListView.OnScrollListener#onScrollStateChanged(android
     * .widget.AbsListView, int)
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (mScrollListener != null) {
            mScrollListener.onScrollStateChanged(view, scrollState);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.widget.AbsListView.OnScrollListener#onScroll(android.widget.
     * AbsListView, int, int, int)
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        mTotalItemCount = totalItemCount;
        if (mScrollListener != null) {
            mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
                    totalItemCount);
        }
    }

    protected 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("松开载入更多");
            } else if (state == STATE_LOADING) {
                mProgressBar.setVisibility(View.VISIBLE);
            } else {
                mHintView.setVisibility(View.VISIBLE);
                mHintView.setText("查看更多");
            }
        }

        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);
        }

    }

}

MainActivity.java对控件的使用

package com.example.test_my_x_list_view;

import android.app.Activity;
import android.os.Bundle;

import com.example.test_my_x_list_view.widget.XListView;
import com.example.test_my_x_list_view.widget.XListView.IXListViewListener;
import com.example.test_my_x_list_view.widget.adapter.MyAdapter;

public class MainActivity extends Activity {

    /** 页面控件 */
    private XListView x_list_view;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        x_list_view = (XListView) findViewById(R.id.x_list_view);
        // 设置可加载更多
        x_list_view.setPullLoadEnable(true);
        // 设置上拉刷新监听
        x_list_view.setXListViewListener(new IXListViewListener() {

            @Override
            public void onLoadMore() {
                // onLoaded();
            }
        });
        // 映射值
        x_list_view.setAdapter(new MyAdapter(getApplicationContext()));
    }
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.test_my_x_list_view.widget.XListView
        android:id="@+id/x_list_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</RelativeLayout>

适配器MyAdapter.java

/* 
 * @(#)MyAdapter.java
 *
 * Copyright 2015, .....
 */
package com.example.test_my_x_list_view.widget.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import com.example.test_my_x_list_view.R;

/**
 * ListView适配器
 * 
 * <p>
 * <b>History:</b>
 * <table border="1">
 * <tr>
 * <th>Date</th>
 * <th>Operator</th>
 * <th>Memo</th>
 * </tr>
 * <tr>
 * <td>2015-5-6</td>
 * <td>Zjc</td>
 * <td>Create</td>
 * </tr>
 * </table>
 * 
 * @author Zjc
 * 
 * @version 1.0.0
 * @since 1.0.0
 */
public class MyAdapter extends BaseAdapter {

    private LayoutInflater inflater;

    /**
     * 默认构造方法
     */
    public MyAdapter(Context context) {
        this.inflater = LayoutInflater.from(context);
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.widget.Adapter#getCount()
     */
    @Override
    public int getCount() {
        return 28;
        // TODO 完成Adapter.getCount方法的构建或覆盖
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.widget.Adapter#getItem(int)
     */
    @Override
    public Object getItem(int position) {
        return null;
        // TODO 完成Adapter.getItem方法的构建或覆盖
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.widget.Adapter#getItemId(int)
     */
    @Override
    public long getItemId(int position) {
        return position;
        // TODO 完成Adapter.getItemId方法的构建或覆盖
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.widget.Adapter#getView(int, android.view.View,
     * android.view.ViewGroup)
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        convertView = inflater.inflate(R.layout.item, parent, false);
        return convertView;
    }
}

item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#607D8B" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="60dp"
        android:gravity="center_vertical" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="列表数据"
            android:textColor="#ffffff"
            android:textSize="14sp" />
    </LinearLayout>

</LinearLayout>

 

posted @ 2015-05-13 17:23  Zjc0514  阅读(165)  评论(0编辑  收藏  举报