148.模拟下拉刷新

设置窗体的样式可以直接在Manifist文件中的style中直接设置 android:theme="@style/AppTheme",这是一个全局App的属性,也可以在activity中设置requestWindowFeature(Window.FEATURE_NO_TITLE);设置没有title的窗体样式。

下拉的时候出现了下拉刷新的字样,需要为拉出的部分单独设计样式

android:indeterminate="true"圆圈的进度条

style="@android:style/Widget.ProgressaBar"圆圈的进度条

style="@android:style/Widget.ProgressaBar.Horizontal"水平进度条

android:indeterminateDrawable="@drawable/indeterminate_drawable"设置自定义的圆圈,在res/drawable目录下创建indeterminate_drawable.xml的样式文件


刷新头部的填充方法如下,这个方法必须在setAdapter前面调用,也就是1.addHeaderView必须在setAdapter之前调用。2.将paddingTop设置一个headerView高度的负值去隐藏它

//初始化头部的填充
View headView = View.inflate(this, R.layout.layout_head, null);
//添加刷新的布局,添加到自定义listView的顶部
refreshListView.addHeaderView(headView);
getHeight()和getMeasuredHeight()的区别:
getMeasuredHeight():获取测量完的高度,只要在onMeasure方法执行完,就可以用它获取到宽高,在自定义控件内部多使用这个使用view.measure(0,0)方法可以主动通知系统去测量,然后就可以直接使用它获取宽高
headView.measure(0, 0);//主动通知系统去测量
int headViewHeight = headView.getMeasuredHeight();
Log.e("MainActivity", "headViewHeight: "+headViewHeight);
headView.setPadding(0, -headViewHeight, 0, 0);
refreshListView.addHeaderView(headerView);
getHeight():必须在onLayout方法执行完后,才能获得宽高
//初始化头部的填充
		final View headView = View.inflate(this, R.layout.layout_head, null);
		//监听headView,xml文件是异步的,一开始没有获取到高度
		headView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
			@Override
			public void onGlobalLayout() {
				//获取到headView高度来,设置隐藏的padding
				int headViewHeight = headView.getHeight();
				//设置padding
				headView.setPadding(0, -headViewHeight, 0, 0);
				//添加刷新的布局,添加到自定义listView的顶部,必须在setAdapter前面调用
				refreshListView.addHeaderView(headView);
			}
		});

下拉刷新通过添加接口来实现监听

	//接口变量创建
	private OnRefreshListener listener;
	public void setOnRefreshListener(OnRefreshListener listener){
		this.listener = listener;
	}
	//创建接口
	public interface OnRefreshListener{
		void onPullRefresh();
		void onLoadingMore();
	}
接口的使用
//监听refreshListView
		refreshListView.setOnRefreshListener(new OnRefreshListener(){
			//松开进入刷新状态
			@Override
			public void onPullRefresh() {
				System.out.println("松开状态进入刷新");
				
			}

			@Override
			public void onLoadingMore() {
				// TODO Auto-generated method stub
				
			}
			
		});
上拉刷新,上拉刷新不需要添加接口直接使用OnScrollListener继承这个接口就可以以了

使用的时候首先初始化滚动监听

//设置一个滚动监听器
setOnScrollListener(this);
再实现接口方法
//滚动的接口方法,滚动状态的改变
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		//SCROLL_STATE_IDLE闲置状态,手指松开的时候的状态
		//SCROLL_STATE_TOUCH_SCROLL:手指触摸滑动,就是按着来滑动
		//SCROLL_STATE_FLING:快速滑动后松开,惯性
		if(scrollState==OnScrollListener.SCROLL_STATE_IDLE 
				&& getLastVisiblePosition()==(getCount()-1) &&!isLoadingMore){
			isLoadingMore = true;
			
			footerView.setPadding(0, 0, 0, 0);//显示出footerView
			setSelection(getCount());//让listview最后一条显示出来
			
			if(listener!=null){
				listener.onLoadingMore();
			}
		}
		
	}
	
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		// TODO Auto-generated method stub
		
	}
使用setSelection(getCount());//让listview的某一条显示在顶端。让最下面的一条显示出来

主布局文件activity_main.xml,使用的自定义布局作为listView

<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"
    tools:context=".MainActivity" >

    <com.ldw.refresh.RefreshListView
        android:id="@+id/refreshListView"
        android:layout_width="match_parent"
    	android:layout_height="wrap_content"
        ></com.ldw.refresh.RefreshListView>

</RelativeLayout>
layout_header.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:gravity="center_horizontal"
    android:orientation="horizontal" >
    
    <RelativeLayout 
        android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:layout_marginTop="20dp"
    	android:layout_marginBottom="20dp"
        >
        <ImageView 
            android:id="@+id/iv_arrow"
            android:layout_width="wrap_content"
    		android:layout_height="wrap_content"
    		android:layout_centerInParent="true"
    		android:background="@drawable/indicator_arrow"
            />
        <ProgressBar 
            android:id="@+id/pb_rotate"
            android:layout_width="40dp"
    		android:layout_height="40dp"
    		android:layout_centerInParent="true"
    		android:indeterminate="true"
    		android:indeterminateDuration="1000"
    		android:indeterminateDrawable="@drawable/indeterminate_drawable"
            />
    </RelativeLayout>
    
	<LinearLayout 
	    android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	 android:orientation="vertical"
    	 android:gravity="center"
    	 android:layout_marginLeft="20dp"
    	 android:layout_marginTop="20dp"
    	android:layout_marginBottom="20dp"
	    >
	    <TextView 
	        android:id="@+id/tv_state"
	        android:layout_width="wrap_content"
	    	android:layout_height="wrap_content"
	    	android:textSize="20sp"
	    	android:textColor="#aa000000"
    		android:text="下拉刷新"
	        />
	    <TextView 
	        android:id="@+id/tv_time"
	        android:layout_width="wrap_content"
	    	android:layout_height="wrap_content"
	    	android:textSize="14sp"
	    	android:textColor="@android:color/darker_gray"
    		android:text="刷新时间"
	        />
	</LinearLayout>
</LinearLayout>

自定义动画indeterminate_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android" 
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:drawable="@drawable/indicate_rotate"
    android:toDegrees="360">
    

</rotate>
尾部的布局layout_tail.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="wrap_content"
    android:gravity="center"
    android:orientation="horizontal" >

    <ProgressBar
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:indeterminate="true"
        android:indeterminateDrawable="@drawable/indeterminate_drawable"
        android:indeterminateDuration="1000" />

    <TextView android:layout_width="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:layout_height="wrap_content"
        android:textColor="#aa000000"
        android:layout_marginLeft="15dp"
        android:textSize="20sp"
        android:text="加载更多..."/>
</LinearLayout>
自定义布局的逻辑文件RefreshListView.java
package com.ldw.refresh;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

/*
 * 自定义listView
 */
public class RefreshListView extends ListView implements OnScrollListener{
	//初始化head
	private View headerView;//headerView
	private int headerViewHeight;//headerView高
	//初始化布局
	private ImageView iv_arrow;
	private ProgressBar pb_rotate;
	private TextView tv_state,tv_time;
	//初始化尾部
	private View footerView;
	private int footerViewHeight;
	
	private int downY;//按下时y坐标
	//下拉刷新的三个状态
	private final int PULL_REFRESH = 0;//下拉刷新的状态head没有拉完
	private final int RELEASE_REFRESH = 1;//松开刷新的状态,head拉完了
	private final int REFRESHING = 2;//正在刷新的状态
	//初始化当前的刷新状态
	private int currentState = PULL_REFRESH;
	//定义旋转动画,向上向下箭头的动画
	private RotateAnimation upAnimation,downAnimation;
	//当前是否正在处于加载更多,默认不是加载更多
	private boolean isLoadingMore = false;
	public RefreshListView(Context context) {
		super(context);
		init();
	}
	
	public RefreshListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	
	private void init(){
		//设置一个滚动监听器
		setOnScrollListener(this);
		initHeadView();
		initRotateAnimation();
		initFooterView();
	}

	//初始化listView的时候添加head
	private void initHeadView() {
		headerView = View.inflate(getContext(), R.layout.layout_head, null);
		iv_arrow = (ImageView) headerView.findViewById(R.id.iv_arrow);
		pb_rotate = (ProgressBar) headerView.findViewById(R.id.pb_rotate);
		tv_state = (TextView) headerView.findViewById(R.id.tv_state);
		tv_time = (TextView) headerView.findViewById(R.id.tv_time);
		
		//通知系统测量view
		headerView.measure(0, 0);
		//获取到高度
		headerViewHeight = headerView.getMeasuredHeight();
		//初始化的时候,设置padding来隐藏head
		headerView.setPadding(0, -headerViewHeight, 0, 0);
		//listView就会有head了
		addHeaderView(headerView);
		
	}
	
	//初始化最下面的加载部分
	private void initFooterView() {
		//填充最下面的部分
		footerView = View.inflate(getContext(), R.layout.layout_footer, null);
		footerView.measure(0, 0);//主动通知系统去测量该view;
		footerViewHeight = footerView.getMeasuredHeight();
		//默认是隐藏起来的
		footerView.setPadding(0, -footerViewHeight, 0, 0);
		//添加到底部
		addFooterView(footerView);
	}
	
	//旋转动画
	private void initRotateAnimation() {
		//动画
		upAnimation = new RotateAnimation(0, -180, 
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		//持续的时间
		upAnimation.setDuration(300);
		//保持结束的状态
		upAnimation.setFillAfter(true);
		downAnimation = new RotateAnimation(-180, -360, 
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		downAnimation.setDuration(300);
		downAnimation.setFillAfter(true);
		
	}
	
	//触摸事件
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
			//按下的时候
			case MotionEvent.ACTION_DOWN:
				downY = (int) ev.getY();
				break;
				//移动的时候
			case MotionEvent.ACTION_MOVE:
				//移动的相对距离
				int deltaY =(int) (ev.getY() - downY);
				//更新padding,出现head移动的现象
				int paddingTop = -headerViewHeight + deltaY;
				//设置新的padding,,当前的position为0的时候不让listView滑动
				//listView下滑的时候走这里deltaY为正,显示headd,最后执行return true
				//listView上移的时候deltaY为负不走这里可以滑动listView
				if(paddingTop>-headerViewHeight && getFirstVisiblePosition()==0){
					headerView.setPadding(0, paddingTop, 0, 0);
					//head全部显示了,状态变为松开刷新
					if(paddingTop>=0 && currentState==PULL_REFRESH){
						//从下拉刷新进入松开刷新状态
						currentState = RELEASE_REFRESH;
						refreshHeaderView();
					}
					//head还没有拉完,状态是下拉刷新
					else if (paddingTop<0 && currentState==RELEASE_REFRESH) {
						//进入下拉刷新状态
						currentState = PULL_REFRESH;
						refreshHeaderView();
					}
					
					//拦截TouchMove,不让listview处理该次move事件,会造成listview无法滑动
					return true;
				}
				break;
				//松开就隐藏head
			case MotionEvent.ACTION_UP:
				//当前的状态是下拉刷新的时候隐藏head
				if(currentState == PULL_REFRESH){
					//隐藏head
				}
				//当前的状态是松开刷新的时候,让head全部显示
				else if (currentState==RELEASE_REFRESH) {
					//head全部显示
					headerView.setPadding(0, 0, 0, 0);
					//状态变为正在刷新
					currentState = REFRESHING;
					refreshHeaderView();
					
					//调用接口方法,需要进行刷新了
					if(listener!=null){
						listener.onPullRefresh();
					}
				}
				break;
		}
		return super.onTouchEvent(ev);
	}
	
	/*
	 * 更据当前的状态更新head的显示
	 */
	private void refreshHeaderView(){
		switch (currentState) {
		case PULL_REFRESH:
			tv_state.setText("下拉刷新");
			iv_arrow.startAnimation(downAnimation);
			break;
		case RELEASE_REFRESH:
			tv_state.setText("松开刷新");
			iv_arrow.startAnimation(upAnimation);
			break;
		case REFRESHING:
			//因为向上的旋转动画有可能没有执行完
			iv_arrow.clearAnimation();
			//箭头消失
			iv_arrow.setVisibility(View.INVISIBLE);
			//进度体哦啊可见
			pb_rotate.setVisibility(View.VISIBLE);
			tv_state.setText("正在刷新...");
			break;
		}
	}
	
	//完成刷新,恢复之前的状态一般是异步加载,在你获取完数据并更新完adater之后,去在UI线程中调用该方法
	//子线程中操作
	public void completeRefresh(){
		if(isLoadingMore){
			//重置footerView状态,隐藏相关条目
			footerView.setPadding(0, -footerViewHeight, 0, 0);
			//可以继续刷新
			isLoadingMore = false;
		}else {
			headerView.setPadding(0, -headerViewHeight, 0, 0);
			//状态改变,由正在刷新变成完成刷新
			currentState = PULL_REFRESH;
			pb_rotate.setVisibility(View.INVISIBLE);
			//箭头消失
			iv_arrow.setVisibility(View.INVISIBLE);
			tv_state.setText("下拉刷新");
			tv_time.setText("最后刷新时间" + getCurrentTime());
		}
	}
	
	//获取时间
	private String getCurrentTime(){
		//时间写的格式如下
		SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
		return format.format(new Date());
	}

	//接口变量创建
	private OnRefreshListener listener;
	public void setOnRefreshListener(OnRefreshListener listener){
		this.listener = listener;
	}
	//创建接口
	public interface OnRefreshListener{
		void onPullRefresh();
		void onLoadingMore();
	}
	
	//滚动的接口方法,滚动状态的改变
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		//SCROLL_STATE_IDLE闲置状态,手指松开的时候的状态
		//SCROLL_STATE_TOUCH_SCROLL:手指触摸滑动,就是按着来滑动
		//SCROLL_STATE_FLING:快速滑动后松开,惯性
		if(scrollState==OnScrollListener.SCROLL_STATE_IDLE 
				&& getLastVisiblePosition()==(getCount()-1) &&!isLoadingMore){
			isLoadingMore = true;
			
			footerView.setPadding(0, 0, 0, 0);//显示出footerView
			setSelection(getCount());//让listview最后一条显示出来
			//使用接口的监听,需要加载更多
			if(listener!=null){
				listener.onLoadingMore();
			}
		}
		
	}
	
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		// TODO Auto-generated method stub
		
	}
	
	

}
页面的逻辑文件MainActivity.java
package com.ldw.refresh;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.ldw.refresh.RefreshListView.OnRefreshListener;

public class MainActivity extends Activity {

	private RefreshListView refreshListView;//初始化自定义listView
	private ArrayList<String> list = new ArrayList<String>();
	private MyAdapter adapter;
	
	private Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			//更新UI
			adapter.notifyDataSetChanged();
			refreshListView.completeRefresh();
		};
	};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        initView();
        initData();
        
    }

	private void initView() {
		//设置没有标题的window样式
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		refreshListView = (RefreshListView) findViewById(R.id.refreshListView);
	}
	
	private void initData() {
		//初始化列表中的数据
		for(int i = 0; i < 20; i++){
			list.add("1300000000" + i);
		}
		
		//初始化头部的填充
		final View headView = View.inflate(this, R.layout.layout_head, null);
		/*在填充自定义的listView中直接实现
		//监听headView,xml文件是异步加载的,一开始没有获取到高度
		headView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
			@Override
			public void onGlobalLayout() {
				headView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
				//获取到headView高度来,设置隐藏的padding
				int headViewHeight = headView.getHeight();
				//设置padding
				headView.setPadding(0, -headViewHeight, 0, 0);
				//添加刷新的布局,添加到自定义listView的顶部,必须在setAdapter前面调用
				refreshListView.addHeaderView(headView);
			}
		});
		*/
		
		//创建adapter,填充listView
		adapter = new MyAdapter();
		refreshListView.setAdapter(adapter);
		
		//监听refreshListView,在创建刷新完listView后调用接口
		refreshListView.setOnRefreshListener(new OnRefreshListener(){
			//松开进入刷新状态
			@Override
			public void onPullRefresh() {
				System.out.println("松开状态进入刷新");
				requestDataFromServer(false);
			}

			@Override
			public void onLoadingMore() {
				//加载更多
				requestDataFromServer(true);
				
			}
			
		});
		
	}
	
	/**
	 * 模拟向服务器请求数据
	 */
	private void requestDataFromServer(final boolean isLoadingMore){
		new Thread(){
			public void run() {
				//模拟请求服务器的一个时间长度,休眠3s
				SystemClock.sleep(3000);
				
				if(isLoadingMore){
					list.add("加载更多的数据-1");
					list.add("加载更多的数据-2");
					list.add("加载更多的数据-3");
				}else {
					list.add(0, "下拉刷新的数据");
				}
				
				//在UI线程更新UI
				handler.sendEmptyMessage(0);
			};
		}.start();
	}
	
	class MyAdapter extends BaseAdapter{

		@Override
		public int getCount() {
			return list.size();
		}

		@Override
		public Object getItem(int position) {
			return null;
		}

		@Override
		public long getItemId(int position) {
			return 0;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			//创建一个TextView控件并设置属性
			TextView textView = new TextView(MainActivity.this);
			//设置内边距
			textView.setPadding(20, 20, 20, 20);
			//设置字体大小
			textView.setTextSize(18);
			//设置文本内容
			textView.setText(list.get(position));
			return textView;
		}
		
	}
    
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值