顾名思义,下拉刷新在安卓应用中随处可见,像新浪微博,QQ等都有运用!~关于这方面的文章也找了好多,但是都是错误百出~~~,http://blog.csdn.net/lilu_leo/article/details/7325383这篇文章写的好是不错的~~~,大家可以看一下关于下拉列表的介绍!
我就是用这个下拉功能,实现的读取文件的实例。本实例可以读取sdcard的文件及其子文件,并针对当前目录进行下拉刷新~~
看一下截图:
关于代码结构截图如下:
来看一下源文件:
PullToRefreshActivity.java
package P_1_RefreshListView2;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import P_1_RefreshListView1.PullToRefreshListView;
import P_1_RefreshListView1.PullToRefreshListView.OnRefreshListener;
import android.app.Activity;
import android.app.ListActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import com.markupartist.android.example.pulltorefresh.R;
public class PullToRefreshActivity extends Activity {
private LinkedList<String> mListItems = new LinkedList<String>();;
private PullToRefreshListView mlistview;
private String readpath="/";//记录每次刷新时,读取的路径
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pull_to_refresh);
textlist("/");
}
private class GetDataTask extends AsyncTask<Void, Void, String[]> {//异步执行任务
/*在开发Android移动客户端的时候往往要使用多线程来进行操作,
我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验。
但是在子线程中无法去操作主线程(UI 线程),在子线程中操作UI线程会出现错误。
因此android提供了一个类Handler来在子线程中来更新UI线程,用发消息的机制更新UI界面,呈现给用户。
这样就解决了子线程更新UI的问题。
但是费时的任务操作总会启动一些匿名的子线程,太多的子线程给系统带来巨大的负担,
随之带来一些性能问题。因此android提供了一个工具类AsyncTask,顾名思义异步执行任务。
这个AsyncTask生来就是处理一些后台的比较耗时的任务,给用户带来良好用户体验的,
从编程的语法上显得优雅了许多,不再需要子线程和Handler就可以完成异步操作并且刷新用户界面。
http://blog.csdn.net/cjjky/article/details/6684959
*/
@Override
protected String[] doInBackground(Void... params) {
// Simulates a background job.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
;
}
return null;
}
@Override
protected void onPostExecute(String[] result) {
// mListItems.addFirst("1");
textlist(readpath);///每次刷新都重新读取一次
// Call onRefreshComplete when the list has been refreshed.
mlistview.onRefreshComplete();
super.onPostExecute(result);
}
}
public void textlist(String ppath){
getFiles(ppath);
// Set a listener to be invoked when the list should be refreshed.
mlistview = ((PullToRefreshListView)PullToRefreshActivity.this.findViewById(R.id.usalist) );
mlistview.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
// TODO Auto-generated method stub
new GetDataTask().execute();
}
});
// mListItems.addAll(Arrays.asList(s));
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, mListItems);
mlistview.setAdapter(adapter);
mlistview.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
// TODO Auto-generated method stub
readpath=mListItems.get(position-1);//注意一定要减一,因为加了一个addHeaderView();
mListItems.clear();///将列表清楚
textlist(readpath);
}
});
}
public void getFiles(String path){//获得文件列表
File file=new File(path);
File [] files=file.listFiles();
if(files==null){
mListItems.add(path);/如果是文件,没有下一集目录,直接添加上,不再改变
}else{
for(File f:files){
mListItems.add(f.getAbsolutePath());/有下一级目录的,把下一级目录全添加上
}
}
}
}
PullToRefreshListView.java
package P_1_RefreshListView1;
import com.markupartist.android.example.pulltorefresh.R;
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.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
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 int mCurrentScrollState;
// 当前刷新状态
private int mRefreshState;
//头视图的高度
private int mRefreshViewHeight;
//头视图 原始的top padding 属性值
private int mRefreshOriginalTopPadding;
private int mLastMotionY;
// 监听对listview的滑动动作
private OnRefreshListener mOnRefreshListener;
//箭头图片
private static int REFRESHICON = R.drawable.goicon;
//listview 滚动监听器
private OnScrollListener mOnScrollListener;
private LayoutInflater mInflater;
private RelativeLayout mRefreshView;
//顶部刷新时出现的控件
private TextView mRefreshViewText;
private ImageView mRefreshViewImage;
private ProgressBar mRefreshViewProgress;
private TextView mRefreshViewLastUpdated;
// 箭头动画效果
//变为向下的箭头
private RotateAnimation mFlipAnimation;
//变为逆向的箭头
private RotateAnimation mReverseFlipAnimation;
//是否反弹
private boolean mBounceHack;
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);
}
/**
* 初始化控件和箭头动画(这里直接在代码中初始化动画而不是通过xml)
*/
private void init(Context context) {
// Load all of the animations we need in code rather than through XML
//第一个参数fromDegrees为动画起始时的旋转角度
//第二个参数toDegrees为动画旋转到的角度
//第三个参数pivotXType为动画在X轴相对于物件位置类型
//第四个参数pivotXValue为动画相对于物件的X坐标的开始位置
//第五个参数pivotXType为动画在Y轴相对于物件位置类型
//第六个参数pivotYValue为动画相对于物件的Y坐标的开始位置
/*http://www.jb51.net/article/32341.htm
* android中提供了4中动画:
AlphaAnimation 透明度动画效果
ScaleAnimation 缩放动画效果
TranslateAnimation 位移动画效果
RotateAnimation 旋转动画效果
详细出处参考:http://www.jb51.net/article/32341.htm
* RotateAnimation:旋转变化动画类
* http://blog.csdn.net/congqingbin/article/details/7889778
*
* RotateAnimation类是Android系统中的旋转变化动画类,用于控制View对象的旋转动作,该类继承于Animation类。RotateAnimation类中的很多方法都与Animation类一致,该类中最常用的方法便是RotateAnimation构造方法。
【基本语法】public RotateAnimation (float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
参数说明
fromDegrees:旋转的开始角度。
toDegrees:旋转的结束角度。
pivotXType:X轴的伸缩模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT。
pivotXValue:X坐标的伸缩值。
pivotYType:Y轴的伸缩模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT。
pivotYValue:Y坐标的伸缩值。
*
* */
mFlipAnimation = new RotateAnimation(0, -180,RotateAnimation.RELATIVE_TO_SELF,
0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);//设置旋转变化动画对象
mFlipAnimation.setInterpolator(new LinearInterpolator());//动画以均匀的速率改变
/* Interpolator的具体使用方法
Interpolator定义了动画变化的速率,在Animations框架当中定义了一下几种Interpolator
AccelerateDecelerateInterpolator:在动画开始与结束的地方速率改变比较慢,在中间的时候速率快。
AccelerateInterpolator:在动画开始的地方速率改变比较慢,然后开始加速
CycleInterpolator:动画循环播放特定的次数,速率改变沿着正弦曲线
DecelerateInterpolator:在动画开始的地方速率改变比较慢,然后开始减速
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);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRefreshView = (RelativeLayout) mInflater.inflate(R.layout.pull_to_refresh_header, this, false);
mRefreshViewText =(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);
mRefreshViewImage =(ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);
mRefreshViewProgress =(ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);
mRefreshViewLastUpdated =(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);
mRefreshViewImage.setMinimumHeight(50);
mRefreshView.setOnClickListener(new OnClickRefreshListener());
mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();
mRefreshState = TAP_TO_REFRESH;
//为listview头部增加一个view
addHeaderView(mRefreshView);
super.setOnScrollListener(this);
measureView(mRefreshView);
mRefreshViewHeight = mRefreshView.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) {
//当前手指的Y值
final int y = (int) event.getY();
mBounceHack = false;
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
//将垂直滚动条设置为可用状态
if (!isVerticalScrollBarEnabled()) {
setVerticalScrollBarEnabled(true);
}
if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
// 拖动距离达到刷新需要
if ((mRefreshView.getBottom() >= mRefreshViewHeight
|| mRefreshView.getTop() >= 0)
&& mRefreshState == RELEASE_TO_REFRESH) {
// 把状态设置为正在刷新
// Initiate the refresh
mRefreshState = REFRESHING; //将标量设置为,正在刷新
// 准备刷新
prepareForRefresh();
// 刷新
onRefresh();
} else if (mRefreshView.getBottom() < mRefreshViewHeight
|| mRefreshView.getTop() <= 0) {
// Abort refresh and scroll down below the refresh view
//停止刷新,并且滚动到头部刷新视图的下一个视图
resetHeader();
setSelection(1); //定位在第二个列表项
}
}
break;
case MotionEvent.ACTION_DOWN:
// 获得按下y轴位置
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
//更行头视图的toppadding 属性
applyHeaderPadding(event);
break;
}
return super.onTouchEvent(event);
}
// 获得header距离
private void applyHeaderPadding(MotionEvent ev) {
//获取累积的动作数
int pointerCount = ev.getHistorySize();
for (int p = 0; p < pointerCount; p++) {
//如果是释放将要刷新状态
if (mRefreshState == RELEASE_TO_REFRESH) {
if (isVerticalFadingEdgeEnabled()) {
setVerticalScrollBarEnabled(false);
}
//历史累积的高度
int historicalY = (int) ev.getHistoricalY(p);
// Calculate the padding to apply, we divide by 1.7 to
// simulate a more resistant effect during pull.
// 计算申请的边距,除以1.7使得拉动效果更好
int topPadding = (int) (((historicalY - mLastMotionY)- mRefreshViewHeight) / 1.7);
mRefreshView.setPadding(
mRefreshView.getPaddingLeft(),
topPadding,
mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
}
}
/**
* Sets the header padding back to original size.
* 将head的边距重置为初始的数值
*/
private void resetHeaderPadding() {
mRefreshView.setPadding(
mRefreshView.getPaddingLeft(),
mRefreshOriginalTopPadding,
mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
/**
* Resets the header to the original state.
* 重置header为之前的状态
*/
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(REFRESHICON);
// Clear the full rotation animation
mRefreshViewImage.clearAnimation();
// Hide progress bar and arrow.
// 隐藏图标和进度条
mRefreshViewImage.setVisibility(View.GONE);
mRefreshViewProgress.setVisibility(View.GONE);
}
}
//测量视图的高度
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_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.
// 在refreshview完全可见时,设置文字为松开刷新,同时翻转箭头
//如果是接触滚动状态,并且不是正在刷新的状态
if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL&& mRefreshState != REFRESHING) {
if (firstVisibleItem == 0) {
//如果显示出来了第一个列表项,显示刷新图片
mRefreshViewImage.setVisibility(View.VISIBLE);
//如果下拉了listiview,则显示上拉刷新动画
if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20|| mRefreshView.getTop() >= 0)
&& mRefreshState != RELEASE_TO_REFRESH) {
mRefreshViewText.setText(R.string.pull_to_refresh_release_label);
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mFlipAnimation);
mRefreshState = RELEASE_TO_REFRESH;
//如果下拉距离不够,则回归原来的状态
} else if (mRefreshView.getBottom() < mRefreshViewHeight + 20
&& mRefreshState != PULL_TO_REFRESH) {
mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);
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);
mBounceHack = true;
} else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {
setSelection(1);
}
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem,visibleItemCount, totalItemCount);
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
mCurrentScrollState = scrollState;
if (mCurrentScrollState == SCROLL_STATE_IDLE) {
mBounceHack = false;
}
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
public void prepareForRefresh() {
resetHeaderPadding(); // 恢复header的边距
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 onRefresh() {
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
}
}
/**
*
* @param lastUpdated Last updated at.
*/
/**
* Resets the list to a normal state after a refresh.
* 重置listview为普通的listview
* @param lastUpdated
* Last updated at.
*/
public void onRefreshComplete(CharSequence lastUpdated) {
setLastUpdated(lastUpdated);
onRefreshComplete();
}
/**
* Resets the list to a normal state after a refresh.
* 重置listview为普通的listview,
*/
public void onRefreshComplete() {
resetHeader();
// If refresh view is visible when loading completes, scroll down to
// the next item.
if (mRefreshView.getBottom() > 0) {
invalidateViews(); //重绘视图
setSelection(1);
}
}
/**
* 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();
}
}
}
public interface OnRefreshListener {
public void onRefresh();
}
}
pull_to_refresh_header.xml
<?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:paddingTop="10dip"
android:paddingBottom="15dip"
android:gravity="center"
android:id="@+id/pull_to_refresh_header"
>
<ProgressBar
android:id="@+id/pull_to_refresh_progress"
android:indeterminate="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dip"
android:layout_marginRight="20dip"
android:layout_marginTop="10dip"
android:visibility="gone"
android:layout_centerVertical="true"
style="@drawable/icon"
/>
<ImageView
android:id="@+id/pull_to_refresh_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dip"
android:layout_marginRight="20dip"
android:visibility="gone"
android:layout_gravity="center"
android:gravity="center"
android:src="@drawable/goicon"
/>
<TextView
android:id="@+id/pull_to_refresh_text"
android:text="@string/pull_to_refresh_tap_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:paddingTop="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
/>
<TextView
android:id="@+id/pull_to_refresh_updated_at"
android:layout_below="@+id/pull_to_refresh_text"
android:visibility="gone"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
/>
</RelativeLayout>
pull_to_refresh.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<!--
The PullToRefreshListView replaces a standard ListView widget.
-->
<P_1_RefreshListView1.PullToRefreshListView
android:id="@+id/usalist"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
>
</P_1_RefreshListView1.PullToRefreshListView>
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.markupartist.android.example.pulltorefresh"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.Light">
<activity android:name="P_1_RefreshListView2.PullToRefreshActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
以上就是全部代码了~~~
源码下载:http://download.csdn.net/detail/zeq9069/6211043