`
于阳生
  • 浏览: 3772 次
  • 性别: Icon_minigender_1
  • 来自: 澄海
最近访客 更多访客>>
社区版块
存档分类
最新评论

下拉刷新

阅读更多
最近学习了下拉刷新的方法,写在这里做个笔记,也跟大家分享一下。


<?xml version="1.0" encoding="utf-8"?>
<!--
     Copyright (C) 2011 Johan Nilsson <http://markupartist.com>

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    android:paddingBottom="15dip"
    android:paddingTop="10dip" >

    <!-- 小型圆形进度条,初始为不可见 -->

    <ProgressBar
        android:id="@+id/pull_to_refresh_progress"
        style="?android:attr/progressBarStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="30dip"
        android:layout_marginRight="20dip"
        android:layout_marginTop="10dip"
        android:indeterminate="true"
        android:visibility="gone" />
    <!-- 下拉刷新的那个箭头 -->

    <ImageView
        android:id="@+id/pull_to_refresh_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="30dip"
        android:layout_marginRight="20dip"
        android:gravity="center"
        android:src="@drawable/ic_pulltorefresh_arrow"
        android:visibility="gone" />
    <!-- 下拉刷新的提示文本 -->

    <TextView
        android:id="@+id/pull_to_refresh_text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:paddingTop="5dip"
        android:text="@string/pull_to_refresh_tap_label"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/pull_to_refresh_updated_at"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/pull_to_refresh_text"
        android:layout_gravity="center"
        android:gravity="center"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:visibility="gone" />

</RelativeLayout>




<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="5sp"
        android:layout_marginRight="5sp"
        android:orientation="horizontal" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_weight="1"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/mycourse_id"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:singleLine="true"
                android:text="001"
                android:visibility="gone"
                android:textSize="14sp" />

            <TextView
                android:id="@+id/mycourse_class_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="小苹果速成2班"
                android:textColor="#475de0"
                android:textSize="12sp" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/mycourse_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center"
                android:text="《小苹果是怎么炼成的10》"
                android:textSize="22sp" />

            <TextView
                android:id="@+id/mycourese_active"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="right"
                android:layout_marginRight="22sp"
                android:text="已购"
                android:textColor="#9ec762"
                android:textSize="10sp" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_weight="1"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/mycourse_date"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_gravity="center"
                android:layout_marginTop="4sp"
                android:gravity="center"
                android:text="每周三下午第7节"
                android:textColor="#e09647"
                android:textSize="12sp" />
        </LinearLayout>
    </LinearLayout>

</RelativeLayout>





<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/loadmore_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:paddingBottom="15dip"
    android:paddingTop="10dip" >

<!--     <Button
        android:id="@+id/loadmore_btn"
        android:layout_width="match_parent"
        android:layout_height="60.0dip"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="0.0dip"
        android:background="@drawable/weibo_list_item_selector"
        android:text="@string/loadmore_label"
        android:textColor="@color/loadmore_btn_selector"
        android:textSize="18.0sp" />
 -->
    <ProgressBar
        android:id="@+id/loadmore_progress"
        style="?android:attr/progressBarStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="30dip"
        android:layout_marginRight="20dip"
        android:layout_marginTop="10dip"
        android:indeterminate="true"
        android:visibility="gone" />

   <TextView
        android:id="@+id/loadmore_text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:paddingTop="5dip"
        android:text="@string/loadmore_label"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textStyle="bold" />

</RelativeLayout>




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

    <com.example.testpulltorefreshlistview.views.PullToRefreshListView
        android:id="@+id/academy_mycourse_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:cacheColorHint="#00000000"
        android:divider="#19000000"
        android:dividerHeight="4dp"
        android:fadingEdge="none"
        android:fastScrollEnabled="false"
        android:footerDividersEnabled="true"
        android:headerDividersEnabled="false"
        android:smoothScrollbar="true" />

</LinearLayout>



MainActivity 类


package com.example.testpulltorefreshlistview;

import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Toast;

import com.example.testpulltorefreshlistview.adapter.MyCourseAdapter;
import com.example.testpulltorefreshlistview.bean.MyCourseBean;
import com.example.testpulltorefreshlistview.constants.Constants;
import com.example.testpulltorefreshlistview.util.GetTime;
import com.example.testpulltorefreshlistview.views.PullToRefreshListView;
import com.example.testpulltorefreshlistview.views.PullToRefreshListView.OnRefreshListener;

/**
 * 主界面
 *@author Changel
 *@version 2014.07.22.1
 * 
 */

public class MainActivity extends Activity {

	private PullToRefreshListView myListView = null;
	private List<MyCourseBean> myList = null;
	private MyCourseAdapter myAdapter = null;
	private Handler mHandler;

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

		mHandler = new Handler() {
			public void handleMessage(Message msg) {
				switch (msg.what) {
				case 0x123:
					myList = (List<MyCourseBean>) msg.obj;
					//设置适配器,刷新列表
					myAdapter = new MyCourseAdapter(MainActivity.this, myList);
					myListView.setAdapter(myAdapter);
					break;
					
				case 0x124:
					myList = (List<MyCourseBean>) msg.obj;
					//设置适配器,刷新列表
					myAdapter = new MyCourseAdapter(MainActivity.this, myList);
					myListView.setAdapter(myAdapter);
					Toast.makeText(MainActivity.this, "刷新成功", Toast.LENGTH_SHORT).show();
					myListView.onRefreshComplete(GetTime.getLocalTime());
					break;
				case 0x125:
					myList = (List<MyCourseBean>) msg.obj;
					//设置适配器,刷新列表
					myAdapter = new MyCourseAdapter(MainActivity.this, myList);
					myListView.setAdapter(myAdapter);
					Toast.makeText(MainActivity.this, "加载成功", Toast.LENGTH_SHORT).show();
					myListView.onRefreshComplete(GetTime.getLocalTime());
					myListView.onLoadMoreComplete();
					break;
				}
			}
		};
		//初始化界面
		initListView();	
		//启动异步线程加载数据
		new LoadMyCourseAsyncTask(MainActivity.this, Constants.FIRST_LOAD, mHandler).execute();

	}
	
	/**
	 * 初始化界面
	 * 绑定下拉刷新和加载更多的监听器
	 * 
	 * */

	public void initListView() {
		myListView = (PullToRefreshListView) findViewById(R.id.academy_mycourse_list);
		myListView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int positon, long arg3) {
				//点击每一项触发的方法
				Toast.makeText(MainActivity.this, "单项点击!", positon-1).show();
			}

		});
		
		myListView.setOnRefreshListener(new OnRefreshListener() {

			@Override
			//下拉时触发的方法
			public void onRefresh() {

				new LoadMyCourseAsyncTask(MainActivity.this, Constants.REFRESH, mHandler).execute();

			}

			@Override
			//点击加载更多触发的方法
			public void onLoadMore() {

				new LoadMyCourseAsyncTask(MainActivity.this, Constants.MORE_LOAD, mHandler).execute();

			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}



LoadMyCourseAsyncTask 类


package com.example.testpulltorefreshlistview;

import java.util.List;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;

import com.example.testpulltorefreshlistview.bean.MyCourseBean;
import com.example.testpulltorefreshlistview.constants.Constants;
import com.example.testpulltorefreshlistview.util.InitData;

/**
 * 
 * 继承AsyncTask类,用异步线程来加载数据,在向主界面发送加载的信息
 * 
 * @author Changel<373386733@qq.com>
 * @version 2014.07.22.1
 * 
 */

public class LoadMyCourseAsyncTask extends
		AsyncTask<String, Integer, List<MyCourseBean>> {
	private Context context;
	private int flag;
	private Handler mHandler;
	private ProgressDialog progressDialog;

	public LoadMyCourseAsyncTask(Context context, int flag, Handler mHandler) {
		this.context = context;
		this.flag = flag;
		this.mHandler = mHandler;
	}

	@Override
	protected void onPostExecute(List<MyCourseBean> result) {

		Message msg = Message.obtain();

		msg.obj = result;
		msg.what = flag;
		mHandler.sendMessage(msg);

		if (flag == Constants.FIRST_LOAD) {
			progressDialog.dismiss();
		}

	}

	@Override
	protected void onPreExecute() {
		if (flag == Constants.FIRST_LOAD) {

			progressDialog = new ProgressDialog(context);
			progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);// 设置进度条的模型,有矩形,圆圈等
			progressDialog.setMessage("正在获取数据");
			progressDialog.onStart();
			progressDialog.show();
		}
	}

	@Override
	protected List<MyCourseBean> doInBackground(String... params) {
			List<MyCourseBean> myCourseList = new InitData().getCourseData();
			return myCourseList;
		
	}
}



InitData 类


package com.example.testpulltorefreshlistview.util;

import java.util.ArrayList;
import java.util.List;
import com.example.testpulltorefreshlistview.bean.MyCourseBean;


/**
 * 
 * 模拟数据
 * 
 * @author Changel<373386733@qq.com>
 * @version 2014.07.22.1
 * 
 */
public class InitData {

	private static int i,isum;
	
	public List<MyCourseBean> getCourseData(){
		
		List<MyCourseBean> list ;
		list = new ArrayList<MyCourseBean>();
		isum = isum + 15;
		for (i=1; i < isum; i++) {
			MyCourseBean myCourseBean = new MyCourseBean();
			myCourseBean.setmClassName("速成班"+i+"班");
			myCourseBean.setmCourseActive("已购买");
			myCourseBean.setmCourseDate("每周三"+"第"+i+"节");
			myCourseBean.setmCourseName("《"+"小苹果是怎么炼成的"+i+"》");
			myCourseBean.setmCourseId(" "+i);
			list.add(myCourseBean);
		}
		
		//模拟网络加载过程
		for (int i = 0; i < 2; i++) {
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		return list;
	}

}


MyCourseAdapter类


package com.example.testpulltorefreshlistview.adapter;

import java.util.List;

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

import com.example.testpulltorefreshlistview.R;
import com.example.testpulltorefreshlistview.bean.MyCourseBean;


/**
 * 
 * 继承BaseAdapter基类,构造一个Adapter来显示list的内容
 * 
 * @author Changel<373386733@qq.com>
 * @version 2014.07.22.1
 * 
 */

public class MyCourseAdapter extends BaseAdapter{
	
	private List<MyCourseBean> list ;
    private LayoutInflater inflater;
    private Context context;
    
	public MyCourseAdapter(Context context ,List<MyCourseBean> list){
		
		this.context = context;
		this.list = list;
		inflater=LayoutInflater.from(context);
	}
	
	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return list.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return list.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		ViewHolder viewHolder;
		if(convertView==null){
			convertView=inflater.inflate(R.layout.my_course_item, null);
		    viewHolder = new ViewHolder(convertView);
		    convertView.setTag(viewHolder);
		}else{
			viewHolder=(ViewHolder) convertView.getTag();
		}
		//将myCourseBean的信息显示在list上
		MyCourseBean myCourseBean = list.get(position);
		viewHolder.getCourseIdTextView().setText(myCourseBean.getmCourseId());
		viewHolder.getDateTextView().setText(myCourseBean.getmCourseDate());
		viewHolder.getClassNameTextView().setText(myCourseBean.getmClassName());
		viewHolder.getCourseNameTextView().setText(myCourseBean.getmCourseName());
		viewHolder.getActiveTextView().setText(myCourseBean.getmCourseActive());
		
		return convertView;
	}
	
	/**
	 * 
	 * 初始化MyCourseAdapter
	 * 
	 */
	
	class ViewHolder{
		
		TextView idTextView;
		TextView dateTextView;
		TextView courseNameTextView;
		TextView classNameTextView;
		TextView activeTextView;
		ImageView image;
		View view;
				
		public ViewHolder(View view){
			
			this.view = view;
		}
		
		public TextView getCourseIdTextView(){
			if(idTextView == null){				
				idTextView = (TextView)view.findViewById(R.id.mycourse_id);
			}
			return idTextView;
		}
		public TextView getDateTextView(){
			if(dateTextView == null){				
				dateTextView = (TextView)view.findViewById(R.id.mycourse_date);
			}		
			return dateTextView;
		}
		public TextView getCourseNameTextView(){
			if(courseNameTextView == null){				
				courseNameTextView = (TextView)view.findViewById(R.id.mycourse_name);
			}		
			return courseNameTextView;
		}
		public TextView getClassNameTextView(){
			if(classNameTextView == null){				
				classNameTextView = (TextView)view.findViewById(R.id.mycourse_class_name);
			}		
			return classNameTextView;
		}
		public TextView getActiveTextView(){
			if(activeTextView == null){				
				activeTextView = (TextView)view.findViewById(R.id.mycourese_active);
			}		
			return activeTextView;
		}
	}
}




GetTime类

package com.example.testpulltorefreshlistview.util;

import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * 
 * 创建一个获取时间的Util,用于获取更新的时间
 * 
 * @author Changel<373386733@qq.com>
 * @version 2014.07.22.1
 * 
 */
public class GetTime {
	
	private static String timeString = null;
	//获取网络时间
	public static String getNetTime() throws Exception{
		//取得资源对象
		URL url = new URL("http://www.bjtime.cn");
		//生成连接对象
		URLConnection uc = url.openConnection();
		//发出连接
		uc.connect();
		long time = uc.getDate();
		Date date = new Date(time); 
		timeString = new SimpleDateFormat("yyyy-MM-dd").format(date).toString();		  
		return timeString;
	}
	
	//获取本地时间
	public static String getLocalTime(){
		
		SimpleDateFormat sm=new SimpleDateFormat("yyyy-MM-dd");
		timeString = sm.format(new Date()).toString();
		System.out.println(timeString);
		return timeString;
	}
}



Constants类


package com.example.testpulltorefreshlistview.constants;

public class Constants {

	public final static int FIRST_LOAD = 0x123;
	public final static int REFRESH = 0x124;
	public final static int MORE_LOAD = 0x125;

}



PullToRefreshListView类 (此类不是自己写的)

package com.example.testpulltorefreshlistview.views;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.example.testpulltorefreshlistview.R;

/**
 * 自定义ListView,实现OnScrollListener接口
 * 此ListView是为实现"下拉刷新"和"上拉加载更多"而定制的,具体效果可参考新浪微博、腾讯微博
 * 
 */
public class PullToRefreshListView extends ListView implements OnScrollListener {

	private static final int TAP_TO_REFRESH = 1; // (未刷新)
	private static final int PULL_TO_REFRESH = 2; // 下拉刷新
	private static final int RELEASE_TO_REFRESH = 3; // 释放刷新
	private static final int REFRESHING = 4; // 正在刷新
	private static final int TAP_TO_LOADMORE = 5; // 未加载更多
	private static final int LOADING = 6; // 正在加载

	private static final String TAG = "PullToRefreshListView";

	private OnRefreshListener mOnRefreshListener; // 刷新监听器

	/**
	 * Listener that will receive notifications every time the list scrolls.
	 */
	private OnScrollListener mOnScrollListener; // 列表滚动监听器
	private LayoutInflater mInflater; // 用于加载布局文件

	private RelativeLayout mRefreshHeaderView; // 刷新视图(也就是头部那部分)
	private TextView mRefreshViewText; // 刷新提示文本
	private ImageView mRefreshViewImage; // 刷新向上向下的那个图片
	private ProgressBar mRefreshViewProgress; // 这里是圆形进度条
	private TextView mRefreshViewLastUpdated; // 最近更新的文本

	private RelativeLayout mLoadMoreFooterView; // 加载更多
	private TextView mLoadMoreText; // 提示文本
	private ProgressBar mLoadMoreProgress; // 加载更多进度条

	private int mCurrentScrollState; // 当前滚动位置
	private int mRefreshState; // 刷新状态
	private int mLoadState; // 加载状态

	private RotateAnimation mFlipAnimation; // 下拉动画
	private RotateAnimation mReverseFlipAnimation; // 恢复动画

	private int mRefreshViewHeight; // 刷新视图高度
	private int mRefreshOriginalTopPadding; // 原始上部间隙
	private int mLastMotionY; // 记录点击位置

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

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

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

	private void init(Context context) {
		// Load all of the animations we need in code rather than through XML
		/** 定义旋转动画 **/
		// 参数:1.旋转开始的角度 2.旋转结束的角度 3. X轴伸缩模式 4.X坐标的伸缩值 5.Y轴的伸缩模式 6.Y坐标的伸缩值
		mFlipAnimation = new RotateAnimation(0, -180,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		mFlipAnimation.setInterpolator(new LinearInterpolator());
		mFlipAnimation.setDuration(250); // 设置持续时间
		mFlipAnimation.setFillAfter(true); // 动画执行完是否停留在执行完的状态
		mReverseFlipAnimation = new RotateAnimation(-180, 0,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
		mReverseFlipAnimation.setDuration(250);
		mReverseFlipAnimation.setFillAfter(true);

		// 获取LayoutInflater实例对象
		mInflater = (LayoutInflater) context
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

		// 加载下拉刷新的头部视图
		mRefreshHeaderView = (RelativeLayout) mInflater.inflate(
				R.layout.pull_to_refresh_header, this, false);
		mRefreshViewText = (TextView) mRefreshHeaderView
				.findViewById(R.id.pull_to_refresh_text);
		mRefreshViewImage = (ImageView) mRefreshHeaderView
				.findViewById(R.id.pull_to_refresh_image);
		mRefreshViewProgress = (ProgressBar) mRefreshHeaderView
				.findViewById(R.id.pull_to_refresh_progress);
		mRefreshViewLastUpdated = (TextView) mRefreshHeaderView
				.findViewById(R.id.pull_to_refresh_updated_at);
		mLoadMoreFooterView = (RelativeLayout) mInflater.inflate(
				R.layout.loadmore_footer, this, false);
		mLoadMoreText = (TextView) mLoadMoreFooterView
				.findViewById(R.id.loadmore_text);
		mLoadMoreProgress = (ProgressBar) mLoadMoreFooterView
				.findViewById(R.id.loadmore_progress);

		mRefreshViewImage.setMinimumHeight(50); // 设置图片最小高度
		mRefreshHeaderView.setOnClickListener(new OnClickRefreshListener());
		mRefreshOriginalTopPadding = mRefreshHeaderView.getPaddingTop();
		mLoadMoreFooterView.setOnClickListener(new OnClickLoadMoreListener());

		mRefreshState = TAP_TO_REFRESH; // 初始刷新状态
		mLoadState = TAP_TO_LOADMORE;

		addHeaderView(mRefreshHeaderView); // 增加头部视图
		addFooterView(mLoadMoreFooterView); // 增加尾部视图

		super.setOnScrollListener(this);

		measureView(mRefreshHeaderView); // 测量视图
		mRefreshViewHeight = mRefreshHeaderView.getMeasuredHeight(); // 得到视图的高度
	}

	@Override
	protected void onAttachedToWindow() {
		setSelection(1); // 设置当前选中的项
	}

	@Override
	public void setAdapter(ListAdapter adapter) {
		super.setAdapter(adapter);

		setSelection(1);
	}

	/**
	 * Set the listener that will receive notifications every time the list
	 * scrolls.
	 * 
	 * @param l
	 *            The scroll listener.
	 */
	@Override
	public void setOnScrollListener(AbsListView.OnScrollListener l) {
		mOnScrollListener = l;
	}

	/**
	 * Register a callback to be invoked when this list should be refreshed.
	 * 注册监听器
	 * 
	 * @param onRefreshListener
	 *            The callback to run.
	 */
	public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
		mOnRefreshListener = onRefreshListener;
	}

	/**
	 * Set a text to represent when the list was last updated.
	 * 设置一个文本来表示最近更新的列表,显示的是最近更新列表的时间
	 * 
	 * @param lastUpdated
	 *            Last updated at.
	 */
	public void setLastUpdated(CharSequence lastUpdated) {
		if (lastUpdated != null) {
			mRefreshViewLastUpdated.setVisibility(View.VISIBLE);
			mRefreshViewLastUpdated.setText("更新于: " + lastUpdated);
		} else {
			mRefreshViewLastUpdated.setVisibility(View.GONE);
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		final int y = (int) event.getY(); // 获取点击位置的Y坐标

		switch (event.getAction()) {
		case MotionEvent.ACTION_UP: // 手指抬起
			if (!isVerticalScrollBarEnabled()) {
				setVerticalScrollBarEnabled(true);
			}
			if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
				if ((mRefreshHeaderView.getBottom() > mRefreshViewHeight || mRefreshHeaderView
						.getTop() >= 0) && mRefreshState == RELEASE_TO_REFRESH) {
					// Initiate the refresh
					mRefreshState = REFRESHING; // 刷新状态
					prepareForRefresh();
					onRefresh();
				} else if (mRefreshHeaderView.getBottom() < mRefreshViewHeight
						|| mRefreshHeaderView.getTop() < 0) {
					// Abort refresh and scroll down below the refresh view
					resetHeader();
					setSelection(1);
				}
			}
			break;
		case MotionEvent.ACTION_DOWN:
			mLastMotionY = y;
			break;
		case MotionEvent.ACTION_MOVE:
			applyHeaderPadding(event);
			break;
		}
		return super.onTouchEvent(event);
	}

	private void applyHeaderPadding(MotionEvent ev) {
		final int historySize = ev.getHistorySize();

		// Workaround for getPointerCount() which is unavailable in 1.5
		// (it's always 1 in 1.5)
		int pointerCount = 1;
		try {
			Method method = MotionEvent.class.getMethod("getPointerCount");
			pointerCount = (Integer) method.invoke(ev);
		} catch (NoSuchMethodException e) {
			pointerCount = 1;
		} catch (IllegalArgumentException e) {
			throw e;
		} catch (IllegalAccessException e) {
			System.err.println("unexpected " + e);
		} catch (InvocationTargetException e) {
			System.err.println("unexpected " + e);
		}

		for (int h = 0; h < historySize; h++) {
			for (int p = 0; p < pointerCount; p++) {
				if (mRefreshState == RELEASE_TO_REFRESH) {
					if (isVerticalFadingEdgeEnabled()) {
						setVerticalScrollBarEnabled(false);
					}

					int historicalY = 0;
					try {
						// For Android > 2.0
						Method method = MotionEvent.class.getMethod(
								"getHistoricalY", Integer.TYPE, Integer.TYPE);
						historicalY = ((Float) method.invoke(ev, p, h))
								.intValue();
					} catch (NoSuchMethodException e) {
						// For Android < 2.0
						historicalY = (int) (ev.getHistoricalY(h));
					} catch (IllegalArgumentException e) {
						throw e;
					} catch (IllegalAccessException e) {
						System.err.println("unexpected " + e);
					} catch (InvocationTargetException e) {
						System.err.println("unexpected " + e);
					}

					// Calculate the padding to apply, we divide by 1.7 to
					// simulate a more resistant effect during pull.
					int topPadding = (int) (((historicalY - mLastMotionY) - mRefreshViewHeight) / 1.7);

					// 设置上、下、左、右四个位置的间隙间隙
					mRefreshHeaderView.setPadding(
							mRefreshHeaderView.getPaddingLeft(), topPadding,
							mRefreshHeaderView.getPaddingRight(),
							mRefreshHeaderView.getPaddingBottom());
				}
			}
		}
	}

	/**
	 * Sets the header padding back to original size. 设置头部填充会原始大小
	 */
	private void resetHeaderPadding() {
		mRefreshHeaderView.setPadding(mRefreshHeaderView.getPaddingLeft(),
				mRefreshOriginalTopPadding,
				mRefreshHeaderView.getPaddingRight(),
				mRefreshHeaderView.getPaddingBottom());
	}

	/**
	 * Resets the header to the original state. 重新设置头部为原始状态
	 */
	private void resetHeader() {
		if (mRefreshState != TAP_TO_REFRESH) {
			mRefreshState = TAP_TO_REFRESH;

			resetHeaderPadding();

			// Set refresh view text to the pull label
			mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);
			// Replace refresh drawable with arrow drawable
			mRefreshViewImage
					.setImageResource(R.drawable.ic_pulltorefresh_arrow);
			// Clear the full rotation animation
			mRefreshViewImage.clearAnimation();
			// Hide progress bar and arrow.
			mRefreshViewImage.setVisibility(View.GONE);
			mRefreshViewProgress.setVisibility(View.GONE);
		}
	}

	/**
	 * 重设ListView尾部视图为初始状态
	 */
	private void resetFooter() {
		if (mLoadState != TAP_TO_LOADMORE) {
			mLoadState = TAP_TO_LOADMORE;

			// 进度条设置为不可见
			mLoadMoreProgress.setVisibility(View.GONE);
			// 按钮的文本替换为“加载更多”
			mLoadMoreText.setText(R.string.loadmore_label);
		}

	}

	/**
	 * 测量视图的大小
	 * 
	 * @param child
	 */
	private void measureView(View child) {
		ViewGroup.LayoutParams p = child.getLayoutParams();
		if (p == null) {
			p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
					ViewGroup.LayoutParams.WRAP_CONTENT);
		}

		int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
		int lpHeight = p.height;
		int childHeightSpec;
		if (lpHeight > 0) {
			childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
					MeasureSpec.EXACTLY);
		} else {
			childHeightSpec = MeasureSpec.makeMeasureSpec(0,
					MeasureSpec.UNSPECIFIED);
		}
		child.measure(childWidthSpec, childHeightSpec);
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		// When the refresh view is completely visible, change the text to say
		// "Release to refresh..." and flip the arrow drawable.
		if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL
				&& mRefreshState != REFRESHING) {
			if (firstVisibleItem == 0) { // 如果第一个可见条目为0
				mRefreshViewImage.setVisibility(View.VISIBLE); // 让指示箭头变得可见
				/** 如果头部视图相对与父容器的位置大于其自身高度+20或者头部视图的顶部位置>0,并且要在刷新状态不等于"释放以刷新" **/
				if ((mRefreshHeaderView.getBottom() > mRefreshViewHeight + 20 || mRefreshHeaderView
						.getTop() >= 0) && mRefreshState != RELEASE_TO_REFRESH) {
					mRefreshViewText
							.setText(R.string.pull_to_refresh_release_label);// 设置刷新文本为"Release to refresh..."
					mRefreshViewImage.clearAnimation(); // 清除动画
					mRefreshViewImage.startAnimation(mFlipAnimation); // 启动动画
					mRefreshState = RELEASE_TO_REFRESH; // 更改刷新状态为“释放以刷新"
				} else if (mRefreshHeaderView.getBottom() < mRefreshViewHeight + 20
						&& mRefreshState != PULL_TO_REFRESH) {
					mRefreshViewText
							.setText(R.string.pull_to_refresh_pull_label);// 设置刷新文本为"Pull to refresh..."
					if (mRefreshState != TAP_TO_REFRESH) {
						mRefreshViewImage.clearAnimation();
						mRefreshViewImage.startAnimation(mReverseFlipAnimation);
					}
					mRefreshState = PULL_TO_REFRESH;
				}
			} else {
				mRefreshViewImage.setVisibility(View.GONE); // 让刷新箭头不可见
				resetHeader(); // 重新设置头部为原始状态
			}
		} else if (mCurrentScrollState == SCROLL_STATE_FLING
				&& firstVisibleItem == 0 && mRefreshState != REFRESHING) {
			setSelection(1);
		}

		if (mOnScrollListener != null) {
			mOnScrollListener.onScroll(view, firstVisibleItem,
					visibleItemCount, totalItemCount);
		}
	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		mCurrentScrollState = scrollState;

		if (mOnScrollListener != null) {
			mOnScrollListener.onScrollStateChanged(view, scrollState);
		}
	}

	/** 为刷新做准备 **/
	public void prepareForRefresh() {
		resetHeaderPadding();

		mRefreshViewImage.setVisibility(View.GONE); // 去掉刷新的箭头
		// We need this hack, otherwise it will keep the previous drawable.
		mRefreshViewImage.setImageDrawable(null);
		mRefreshViewProgress.setVisibility(View.VISIBLE); // 圆形进度条变为可见

		// Set refresh view text to the refreshing label
		mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);

		mRefreshState = REFRESHING;
	}

	/** 为加载更多做准备 **/
	public void prepareForLoadMore() {
		mLoadMoreProgress.setVisibility(View.VISIBLE);
		mLoadMoreText.setText(R.string.loading_label);
		mLoadState = LOADING;
	}

	public void onRefresh() {
		Log.d(TAG, "onRefresh");

		if (mOnRefreshListener != null) {
			mOnRefreshListener.onRefresh();
		}
	}

	public void OnLoadMore() {
		Log.d(TAG, "onLoadMore");
		if (mOnRefreshListener != null) {
			mOnRefreshListener.onLoadMore();
		}
	}

	/**
	 * Resets the list to a normal state after a refresh.
	 * 
	 * @param lastUpdated
	 *            Last updated at.
	 */
	public void onRefreshComplete(CharSequence lastUpdated) {
		setLastUpdated(lastUpdated); // 显示更新时间
		onRefreshComplete();
	}

	/**
	 * Resets the list to a normal state after a refresh.
	 */
	public void onRefreshComplete() {
		Log.d(TAG, "onRefreshComplete");

		resetHeader();

		// If refresh view is visible when loading completes, scroll down to
		// the next item.
		if (mRefreshHeaderView.getBottom() > 0) {
			invalidateViews();
			setSelection(1);
		}
	}

	public void onLoadMoreComplete() {
		Log.d(TAG, "onLoadMoreComplete");
		resetFooter();
	}

	/**
	 * Invoked when the refresh view is clicked on. This is mainly used when
	 * there's only a few items in the list and it's not possible to drag the
	 * list. 点击刷新
	 */
	private class OnClickRefreshListener implements OnClickListener {

		@Override
		public void onClick(View v) {
			if (mRefreshState != REFRESHING) {
				prepareForRefresh();
				onRefresh();
			}
		}

	}

	/**
	 * 
	 * 加载更多
	 */
	private class OnClickLoadMoreListener implements OnClickListener {

		@Override
		public void onClick(View v) {
			if (mLoadState != LOADING) {
				prepareForLoadMore();
				OnLoadMore();
			}
		}
	}

	/**
	 * Interface definition for a callback to be invoked when list should be
	 * refreshed. 接口定义一个回调方法当列表应当被刷新
	 */
	public interface OnRefreshListener {
		/**
		 * Called when the list should be refreshed. 当列表应当被刷新是调用这个方法
		 * <p>
		 * A call to {@link PullToRefreshListView #onRefreshComplete()} is
		 * expected to indicate that the refresh has completed.
		 */
		public void onRefresh();

		public void onLoadMore();
	}
}


分享到:
评论

相关推荐

    仿QQ下拉刷新

    【仿QQ下拉刷新】是一种常见的移动应用交互设计,它让用户在顶部下拉时触发页面内容的刷新。这种设计在QQ等社交应用中被广泛采用,后来成为了许多Android和iOS应用的标准特性。实现这一功能主要涉及到滚动视图、动画...

    Android 开源的下拉刷新 Eclipse版本

    在Android开发中,"下拉刷新"是一种常见的用户体验设计,让用户可以轻松地更新应用程序中的数据。这个开源项目特别针对Eclipse IDE,意味着开发者无需切换到Android Studio也能利用此功能。以下将详细介绍这个开源...

    IOS下拉刷新Demo实现

    在iOS开发中,下拉刷新(Pull-to-Refresh)是一种常见的用户交互模式,它允许用户通过在列表顶部向下拉动来加载更多数据或更新现有数据。本教程将介绍如何使用EGOTableViewPullRefresh开源库在iOS应用中实现下拉刷新...

    微信小程序scroll-view下拉刷新(附带下拉刷新效果)

    在本教程中,我们将探讨如何在`scroll-view`中实现下拉刷新(Pull-to-Refresh)功能,同时提供一个具体的效果展示。 首先,`scroll-view`是微信小程序提供的一个可滚动视图容器,它支持水平滚动和垂直滚动。通过...

    ScrollView实现下拉刷新

    "ScrollView实现下拉刷新"这个主题聚焦于如何在滚动视图中添加一个下拉刷新功能,这通常用于列表或者网格视图,使得用户可以更新内容而无需离开当前页面。这种特性在许多应用程序中非常常见,比如社交媒体应用和新闻...

    仿网易下拉刷新

    在移动应用开发中,"仿网易下拉刷新"是一种常见的用户体验设计,主要用于更新内容或加载新数据。这种功能让用户能够通过简单的手势从顶部向下拉动列表,触发数据的刷新操作。通常,这种设计会伴随着动画效果,如加载...

    最简单的下拉刷新

    下拉刷新功能是移动应用和网页中常见的交互设计,它允许用户通过向下拉动内容区域来刷新数据。在Android开发中,实现下拉刷新通常需要对ListView或者RecyclerView进行扩展,但根据给定的描述,这里介绍的方法是相对...

    仿美团下拉刷新

    在移动应用开发中,"仿美团下拉刷新"是一个常见的功能设计,主要目的是提供一个用户友好的界面,让用户能够轻松地获取更新的数据。这个功能在美团、大众点评等生活服务类应用中广泛应用,增强了用户的交互体验。下面...

    自定义listview下拉刷新上拉加载更多以及与google官方的下拉刷新结合使用

    在Android开发中,ListView是常用的数据展示控件,但原生的ListView并不支持下拉刷新和上拉加载更多的功能。为了实现这些高级特性,开发者通常需要进行自定义或者使用第三方库。本教程将探讨如何自定义ListView实现...

    Androidstudio下ListView下拉刷新

    然而,为了提供更好的用户体验,许多应用都引入了下拉刷新的功能,使得用户在顶部拉动列表时可以更新数据。本教程将指导你在Android Studio中为ListView实现下拉刷新功能。 1. **下拉刷新概念** 下拉刷新(Pull-to...

    Android自定义上拉加载下拉刷新控件

    在Android开发中,上拉加载和下拉刷新是常见的组件功能,用于提升用户体验,使得用户在滚动列表到顶部时能够方便地获取更多数据,而在滚动到底部时加载更多内容。本示例“Android自定义上拉加载下拉刷新控件”提供了...

    下拉刷新的实现

    在移动应用开发中,"下拉刷新"是一个常见的功能,特别是在列表或滚动视图中,用户可以通过下拉屏幕顶部来获取最新的数据。这个功能让用户在不离开当前界面的情况下获取更新,提高了用户体验。本文将深入探讨如何实现...

    Android 之WebView实现下拉刷新和其他相关刷新功能

    有时候,为了提升用户体验,我们希望在WebView中实现下拉刷新的功能,就像原生的ListView或RecyclerView那样。本篇文章将深入探讨如何在Android的WebView中实现这一特性。 首先,下拉刷新是一种常见的用户界面设计...

    jQuery移动端下拉刷新、上拉加载更多插件

    在移动设备上,为了优化用户体验,许多网页应用都采用了下拉刷新(Pull-to-Refresh)和上拉加载更多(Infinite Scroll)的功能。jQuery作为一款广泛使用的JavaScript库,提供了丰富的插件来支持这些特性。本篇文章将...

    一个快速和强大的前端下拉刷新

    在前端开发中,下拉刷新(Pull-to-Refresh)是一种常见的交互设计,用户可以通过在页面顶部或底部向下拉动来触发数据的更新。这种功能在移动应用和网页中广泛使用,特别是在内容流、列表或者时间线类的应用场景。"一...

    几种方法实现下拉刷新,上拉加载

    在Android应用开发中,下拉刷新和上拉加载是提高用户体验的重要特性,它们使得用户能够方便地获取更多数据而无需离开当前界面。本篇将详细讲解如何使用Android Studio实现这三种不同的下拉刷新和上拉加载功能:...

    webview的下拉刷新

    "webview的下拉刷新"是指在用户下拉Webview时,触发页面的重新加载,类似于UITableView的下拉刷新功能。这个特性提供了用户体验上的便利,让用户能够轻松获取到最新更新的内容。 在iOS中,有两种主要类型的Webview...

    5种uni-app 页面下拉刷新方法-源码示例.zip

    在uni-app中,页面的下拉刷新功能是用户界面交互中常见且重要的一个部分,它通常用于加载更多数据或更新内容。本资料"5种uni-app 页面下拉刷新方法-源码示例.zip"提供了五种不同的实现方式,让我们详细探讨这些方法...

    微信小程序 下拉刷新,tab切换 (源码)

    微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab...

    Android自带下拉刷新的代码例子

    在Android开发中,下拉刷新是一项常见的功能,它允许用户通过在列表顶部向下拉动来刷新内容。Android系统自API 19(KitKat)开始引入了一个名为`SwipeRefreshLayout`的原生控件,用于实现这一交互。这个控件通常与`...

Global site tag (gtag.js) - Google Analytics