自定义控件之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>



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值