天天看點

自定義控件之ListView下拉重新整理

自定義控件之ListView下拉重新整理

1.定義個類繼承ListView

   添加頭條目

   添加腳條目

   設定滾動監聽(處理上啦加載)

   重寫觸摸 事件(處理下拉重新整理)

public class PullToReFreshListView extends ListView implements OnScrollListener {

	private View headerView;
	private int headermeasuredHeight;
	private RotateAnimation up;
	private RotateAnimation down;
	private int downY;
	/** 下拉重新整理 **/
	public static final int PULL_DOWN = 1;
	/** 松開重新整理 **/
	public static final int RELEASE_REFRESH = 2;
	/** 正在重新整理 **/
	public static final int REGFRESHING = 3;
	/** 目前的狀态 **/
	public static int CURRENTSTATE = PULL_DOWN;
	private ImageView mArrow;
	private ProgressBar mPb;
	private TextView mText;

	private int footermeasuredHeight;
	private View footerview;
	
	/**是否加載更多,true:加載更多,false:沒有加載更多**/
	private boolean isLoadMore;

	public PullToReFreshListView(Context context) {
		// super(context);
		this(context, null);
	}

	public PullToReFreshListView(Context context, AttributeSet attrs) {
		// super(context, attrs);
		this(context, attrs, 0);
	}

	public PullToReFreshListView(Context context, AttributeSet attrs,
			int defStyle) {
		super(context, attrs, defStyle);

		// 添加重新整理頭
		addHeader();
		// 添加底部條目
		addFooter();
		// 監聽listview的滾動狀态
		setOnScrollListener(this);
	}

	/**
	 * 添加listview底部條目 2016-8-14 上午11:34:23
	 */
	private void addFooter() {
		footerview = View.inflate(getContext(), R.layout.footer_item, null);

		// 隐藏底部條目
		footerview.measure(0, 0);
		footermeasuredHeight = footerview.getMeasuredHeight();
		footerview.setPadding(0, 0, 0, -footermeasuredHeight);

		addFooterView(footerview);// 添加listview的底部條目
	}

	/**
	 * 添加listview的重新整理頭 2016-8-14 上午9:53:18
	 */
	private void addHeader() {

		headerView = View.inflate(getContext(), R.layout.header_item, null);

		// 初始化控件
		mArrow = (ImageView) headerView.findViewById(R.id.arrow);
		mPb = (ProgressBar) headerView.findViewById(R.id.pb);
		mText = (TextView) headerView.findViewById(R.id.text);

		// 隐藏重新整理頭
		headerView.measure(0, 0);// 測量控件  測量規格為未指定
		headermeasuredHeight = headerView.getMeasuredHeight();
		headerView.setPadding(0, -headermeasuredHeight, 0, 0);

		addHeaderView(headerView);// 将view對象,添加到listview的頭部

		initAnimation();
	}

	/**
	 * 初始化動畫 2016-8-14 上午10:19:53
	 */
	private void initAnimation() {
		// 箭頭向上
		up = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
				Animation.RELATIVE_TO_SELF, 0.5f);
		up.setDuration(500);
		up.setFillAfter(true);// 保持動畫結束的狀态
		// 箭頭向下
		down = new RotateAnimation(-180, -360, Animation.RELATIVE_TO_SELF,
				0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		down.setDuration(500);
		down.setFillAfter(true);// 保持動畫結束的狀态
	}

	// 下拉顯示重新整理頭操作
	// 1.觸摸listview
	// 2.下拉操作
	// 3.判斷目前界面顯示的第一個條目是否是listview的第一個條目,是下拉顯示重新整理頭,不是,顯示顯示listview的其他條目

	// 1.觸摸listview
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// 2.下拉操作
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			downY = (int) ev.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			int moveY = (int) ev.getY();
			int distance = moveY - downY;
			// 判斷是否是下拉操作
			// 3.判斷目前界面顯示的第一個條目是否是listview的第一個條目,是下拉顯示重新整理頭,不是,顯示顯示listview的其他條目
			// getFirstVisiblePosition : 擷取目前界面顯示的第一個條目的位置
			if (distance > 0 && getFirstVisiblePosition() == 0) {
				// 實作下拉顯示重新整理頭
				// 計算空白的區域
				// 空白的區域 = 下拉的距離 - 重新整理頭的高度
				int paddingTop = distance - headermeasuredHeight;
				headerView.setPadding(0, paddingTop, 0, 0);

				// 下拉重新整理 -> 松開重新整理
				if (paddingTop > 0 && CURRENTSTATE == PULL_DOWN) {
					CURRENTSTATE = RELEASE_REFRESH;
					switchOption();
				}
				// 松開重新整理 -> 下拉重新整理
				if (paddingTop < 0 && CURRENTSTATE == RELEASE_REFRESH) {
					CURRENTSTATE = PULL_DOWN;
					switchOption();
				}
				// 因為系統的listview無法顯示空白區域的,是以使用系統的觸摸事件會出問題,解決:不使用
				return true;
			}
			break;
		case MotionEvent.ACTION_UP:
			// 松開重新整理 -> 正在重新整理,并且顯示重新整理頭
			if (CURRENTSTATE == RELEASE_REFRESH) {
				CURRENTSTATE = REGFRESHING;
				headerView.setPadding(0, 0, 0, 0);
				switchOption();

				// 重新整理資料
				if (onRefreshListener != null) {
					onRefreshListener.regresh();
				}
			}
			// 下拉重新整理 -> 隐藏重新整理頭
			if (CURRENTSTATE == PULL_DOWN) {
				headerView.setPadding(0, -headermeasuredHeight, 0, 0);
				
			}
			break;
		}
		// 因為隻有是下拉顯示空白區域的時候才需要不使用系統的觸摸事件,但是如果下拉不是空白區域,還是要使用系統的觸摸事件,來實作下拉顯示其他條目的操作的
		return super.onTouchEvent(ev);
	}

	/**
	 * 根據狀态更改控件的顯示内容 2016-8-14 上午10:55:45
	 */
	private void switchOption() {
		switch (CURRENTSTATE) {
		case PULL_DOWN:
			// 下拉重新整理
			mText.setText("下拉重新整理");
			mArrow.startAnimation(down);
			break;
		case RELEASE_REFRESH:
			// 松開重新整理
			mText.setText("松開重新整理");
			mArrow.startAnimation(up);
			break;
		case REGFRESHING:
			// 正在重新整理
			mText.setText("正在重新整理");
			mArrow.clearAnimation();// 清除動畫
			mArrow.setVisibility(View.GONE);
			mPb.setVisibility(View.VISIBLE);
			break;
		}
	}

	// 取消重新整理
	/**
	 * 取消重新整理 2016-8-14 上午11:25:34
	 */
	public void finish() {
		// 正在重新整理 -> 下拉重新整理,并且隐藏重新整理頭
		if (CURRENTSTATE == REGFRESHING) {
			CURRENTSTATE = PULL_DOWN;
			mText.setText("下拉重新整理");
			mPb.setVisibility(View.GONE);
			mArrow.setVisibility(View.VISIBLE);

			headerView.setPadding(0, -headermeasuredHeight, 0, 0);
		}
		
		//取消加載更多
		//因為取消下拉重新整理和上拉加載是在一個方法中,為了避免取消下拉重新整理的時候,同時也會取消上拉加載,設定是否加載更多的标示
		if (isLoadMore) {
			footerview.setPadding(0, 0, 0, -footermeasuredHeight);
			isLoadMore = false;
		}
		
	}

	// 加載更多
	// 1.監聽listview的滾動狀态,如果是停止滾動,顯示加載更多條目,
	// 2.上拉到listview的最後一個條目

	// 當listview滾動狀态改變的時候調用的方法
	// scrollState : listview滾動的狀态
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		// 監聽listview的滾動狀态,如果是停止滾動,顯示加載更多條目,上拉到listview的最後一個條目
		if (scrollState == OnScrollListener.SCROLL_STATE_IDLE
				&& getLastVisiblePosition() == getCount() - 1 && isLoadMore == false) {
			isLoadMore = true;
			// 顯示加載更多條目
			footerview.setPadding(0, 0, 0, 0);
			// 重新定位listview顯示的最後一個條目
			setSelection(getCount() - 1);// 跳轉到listview的哪個條目,position : 條目的位置

			// 加載更多資料
			if (onRefreshListener != null) {
				onRefreshListener.loadmore();
			}
		}
	}

	// 當listview滾動的時候調用的方法
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		// TODO Auto-generated method stub

	}

	// 回調函數實作重新整理資料操作

	// 3.建立儲存接口實作對象的變量
	public OnRefreshListener onRefreshListener;

	// 2.建立擷取接口實作對象的方法
	public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
		this.onRefreshListener = onRefreshListener;
	}

	// 1.建立接口
	public interface OnRefreshListener {
		/** 下拉重新整理 **/
		public void regresh();
		/**加載更多資料**/
		public void loadmore();
	}
           

2.activity

public class MainActivity extends Activity {

    private PullToReFreshListView mListView;
    
    private int m;
    
    private int n;
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        initView();
    }
    /**
     * 初始化控件
     * 2016-8-14 上午9:31:39
     */
	private void initView() {
		mListView = (PullToReFreshListView) findViewById(R.id.listview);
		
		final List<String> list = new ArrayList<String>();
		//填充資料
		for (int i = 0; i < 10; i++) {
			list.add("德瑪西亞"+i+"區");
		}
		
		final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
		mListView.setAdapter(arrayAdapter);
		
		//重新整理資料操作
		mListView.setOnRefreshListener(new OnRefreshListener() {
			
			@Override
			public void regresh() {
				//加載資料
				//延遲一段時間,加載資料
				new Handler().postDelayed(new Runnable() {
					
					@Override
					public void run() {
						//list.add("艾歐尼亞"+(++m)+"區");
						list.add(0, "艾歐尼亞"+(++m)+"區");//将資料添加list集合的哪個位置,location : 位置  object:添加的資料
						//重新整理界面
						arrayAdapter.notifyDataSetChanged();
						//取消重新整理
						mListView.finish();
					}
				}, 3000);//delayMillis : 延遲時間    Runnable : 執行的操作
			}

			@Override
			public void loadmore() {
				//延遲一段時間,加載資料
				new Handler().postDelayed(new Runnable() {
					
					@Override
					public void run() {
						//list.add("艾歐尼亞"+(++m)+"區");
						list.add("黑色玫瑰"+(++n)+"區");//将資料添加list集合的哪個位置,location : 位置  object:添加的資料
						//重新整理界面
						arrayAdapter.notifyDataSetChanged();
						//取消重新整理
						mListView.finish();
					}
				}, 3000);//delayMillis : 延遲時間    Runnable : 執行的操作
			}
		});
	}
           

3.布局檔案

<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.itheima.pulltorefreshlistview.PullToReFreshListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="@android:color/darker_gray"
        android:dividerHeight="0.5dp"
        ></com.itheima.pulltorefreshlistview.PullToReFreshListView>

</RelativeLayout>
           

4.頭條目布局

<?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="wrap_content"
    android:orientation="horizontal" 
    android:padding="6dp"
    >
    
    <RelativeLayout 
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginLeft="20dp"
        >
        <ImageView 
            android:id="@+id/arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/arrow"
            android:layout_centerInParent="true"
            />
        <ProgressBar 
            android:id="@+id/pb"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_centerInParent="true"
            android:indeterminateDrawable="@drawable/progressbarstyle"
            android:visibility="gone"
            />
    </RelativeLayout>
    
    
    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center_vertical"
        android:gravity="center_vertical|center_horizontal"
        >
        <!-- | : 加意思,兩種效果全部生效 -->
        <TextView 
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下拉重新整理"
            android:textColor="#FF0000"
            />
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="最後刷時間:2016-08-14 09:48:06"
            android:textColor="@android:color/darker_gray"
            />
    </LinearLayout>
</LinearLayout>
           

5.腳條目布局檔案

<?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="wrap_content"
    android:orientation="horizontal" 
    android:gravity="center"
    >
    
     <ProgressBar 
            android:id="@+id/pb"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:indeterminateDrawable="@drawable/progressbarstyle"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            />
     
     <TextView 
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="加載更多..."
            android:textColor="#FF0000"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="10dp"
            />

</LinearLayout>
           

繼續閱讀