使用ListView来做下拉刷新有很多例子,而且封装的很好。
ListView有 header 但是如果不使用ListView的下拉刷新网上的例子相对来说比较少,于是自己动手写了个,原理差不多,主要都是在OnTouchListener
首先是Header的布局文件:
- <?xml version="1.0" encoding="utf-8"?>
- <!-- ListView的头部 -->
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/head_rootLayout"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content" >
- <!-- 内容 -->
- <RelativeLayout
- android:id="@+id/head_contentLayout"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="30dp" >
- <!-- 箭头图像、进度条 -->
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true" >
- <!-- 箭头 -->
- <ImageView
- android:id="@+id/head_arrowImageView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:contentDescription="@string/app_name"
- android:src="@drawable/head_arrow" />
- <!-- 进度条 -->
- <ProgressBar
- android:id="@+id/head_progressBar"
- style="?android:attr/progressBarStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:visibility="gone" />
- </FrameLayout>
- <!-- 提示、最近更新 -->
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:gravity="center_horizontal"
- android:orientation="vertical" >
- <!-- 提示 -->
- <TextView
- android:id="@+id/head_tipsTextView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/pulltorefresh"
- android:textSize="20sp" />
- <!-- 最近更新 -->
- <TextView
- android:id="@+id/head_lastUpdatedTextView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/lastupdate"
- android:textColor="#cc6600"
- android:textSize="12sp" />
- </LinearLayout>
- </RelativeLayout>
- </LinearLayout>
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical"
- android:id="@+id/globleLayout">
- <ScrollView
- android:id="@+id/scrollView"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" >
- <span style="white-space:pre"> </span><!-- 这里放你想要放的布局 --!>
- <LinearLayout
- android:id="@+id/linearLayout"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
- <ImageView
- android:layout_width="80dp"
- android:layout_height="120dp"
- android:src="@drawable/a" />
- <ImageView
- android:layout_width="80dp"
- android:layout_height="120dp"
- android:src="@drawable/b" />
- <ImageView
- android:layout_width="80dp"
- android:layout_height="120dp"
- android:src="@drawable/c" />
- <ImageView
- android:layout_width="80dp"
- android:layout_height="120dp"
- android:src="@drawable/d" />
- <ImageView
- android:layout_width="80dp"
- android:layout_height="120dp"
- android:src="@drawable/e" />
- <ImageView
- android:layout_width="80dp"
- android:layout_height="120dp"
- android:src="@drawable/f" />
- </LinearLayout>
- </ScrollView>
- </LinearLayout>
现在是Activity 的代码:
- package com.example.scrollviewtest;
- import java.util.Date;
- import android.app.Activity;
- import android.content.Context;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.View.MeasureSpec;
- import android.view.View.OnTouchListener;
- import android.view.ViewGroup;
- import android.view.ViewGroup.LayoutParams;
- import android.view.animation.LinearInterpolator;
- import android.view.animation.RotateAnimation;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.ProgressBar;
- import android.widget.ScrollView;
- import android.widget.TextView;
- public class MainActivity extends Activity {
- private ScrollView sc;
- private LinearLayout header;
- private ImageView arrowImg;
- private ProgressBar headProgress;
- private TextView lastUpdateTxt;
- private TextView tipsTxt;
- private RotateAnimation tipsAnimation;
- private RotateAnimation reverseAnimation;
- private LayoutInflater inflater;
- private LinearLayout globleLayout;
- private int headerHeight; //头高度
- private int lastHeaderPadding; //最后一次调用Move Header的Padding
- private boolean isBack; //从Release 转到 pull
- private int headerState = DONE;
- static final private int RELEASE_To_REFRESH = 0;
- static final private int PULL_To_REFRESH = 1;
- static final private int REFRESHING = 2;
- static final private int DONE = 3;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- init(this);
- }
- private void init(Context context) {
- globleLayout = (LinearLayout) findViewById(R.id.globleLayout);
- sc = (ScrollView) globleLayout.findViewById(R.id.scrollView);
- inflater = (LayoutInflater) this
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- header = (LinearLayout) inflater.inflate(R.layout.drag_drop_header, null);
- measureView(header);
- headerHeight = header.getMeasuredHeight();
- lastHeaderPadding = (-1*headerHeight); //最后一次调用Move Header的Padding
- header.setPadding(0, lastHeaderPadding, 0, 0);
- header.invalidate();
- globleLayout.addView(header,0);
- headProgress = (ProgressBar) findViewById(R.id.head_progressBar);
- arrowImg = (ImageView) findViewById(R.id.head_arrowImageView);
- arrowImg.setMinimumHeight(50);
- arrowImg.setMinimumWidth(50);
- tipsTxt = (TextView) findViewById(R.id.head_tipsTextView);
- lastUpdateTxt = (TextView) findViewById(R.id.head_lastUpdatedTextView);
- //箭头转动动画
- tipsAnimation = new RotateAnimation(0, -180,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f);
- tipsAnimation.setInterpolator(new LinearInterpolator());
- tipsAnimation.setDuration(200); //动画持续时间
- tipsAnimation.setFillAfter(true); //动画结束后保持动画
- //箭头反转动画
- reverseAnimation = new RotateAnimation(-180, 0,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f);
- reverseAnimation.setInterpolator(new LinearInterpolator());
- reverseAnimation.setDuration(200);
- reverseAnimation.setFillAfter(true);
- //为scrollview绑定事件
- sc.setOnTouchListener(new OnTouchListener() {
- private int beginY;
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_MOVE:
- //sc.getScrollY == 0 scrollview 滑动到头了
- //lastHeaderPadding > (-1*headerHeight) 表示header还没完全隐藏起来时
- //headerState != REFRESHING 当正在刷新时
- if((sc.getScrollY() == 0 || lastHeaderPadding > (-1*headerHeight)) && headerState != REFRESHING) {
- //拿到滑动的Y轴距离
- int interval = (int) (event.getY() - beginY);
- //是向下滑动而不是向上滑动
- if (interval > 0) {
- interval = interval/2;//下滑阻力
- lastHeaderPadding = interval + (-1*headerHeight);
- header.setPadding(0, lastHeaderPadding, 0, 0);
- if(lastHeaderPadding > 0) {
- //txView.setText("我要刷新咯");
- headerState = RELEASE_To_REFRESH;
- //是否已经更新了UI
- if(! isBack) {
- isBack = true; //到了Release状态,如果往回滑动到了pull则启动动画
- changeHeaderViewByState();
- }
- } else {
- headerState = PULL_To_REFRESH;
- changeHeaderViewByState();
- //txView.setText("看到我了哦");
- //sc.scrollTo(0, headerPadding);
- }
- }
- }
- break;
- case MotionEvent.ACTION_DOWN:
- //加上下滑阻力与实际滑动距离的差(大概值)
- beginY = (int) ((int) event.getY() + sc.getScrollY()*1.5);
- break;
- case MotionEvent.ACTION_UP:
- if (headerState != REFRESHING) {
- switch (headerState) {
- case DONE:
- //什么也不干
- break;
- case PULL_To_REFRESH:
- headerState = DONE;
- lastHeaderPadding = -1*headerHeight;
- header.setPadding(0, lastHeaderPadding, 0, 0);
- changeHeaderViewByState();
- break;
- case RELEASE_To_REFRESH:
- isBack = false; //准备开始刷新,此时将不会往回滑动
- headerState = REFRESHING;
- changeHeaderViewByState();
- onRefresh();
- break;
- default:
- break;
- }
- }
- break;
- }
- //如果Header是完全被隐藏的则让ScrollView正常滑动,让事件继续否则的话就阻断事件
- if(lastHeaderPadding > (-1*headerHeight) && headerState != REFRESHING) {
- return true;
- } else {
- return false;
- }
- }
- });
- }
- private void changeHeaderViewByState() {
- switch (headerState) {
- case PULL_To_REFRESH:
- // 是由RELEASE_To_REFRESH状态转变来的
- if (isBack) {
- isBack = false;
- arrowImg.startAnimation(reverseAnimation);
- tipsTxt.setText("下拉刷新");
- }
- tipsTxt.setText("下拉刷新");
- break;
- case RELEASE_To_REFRESH:
- arrowImg.setVisibility(View.VISIBLE);
- headProgress.setVisibility(View.GONE);
- tipsTxt.setVisibility(View.VISIBLE);
- lastUpdateTxt.setVisibility(View.VISIBLE);
- arrowImg.clearAnimation();
- arrowImg.startAnimation(tipsAnimation);
- tipsTxt.setText("松开刷新");
- break;
- case REFRESHING:
- lastHeaderPadding = 0;
- header.setPadding(0, lastHeaderPadding, 0, 0);
- header.invalidate();
- headProgress.setVisibility(View.VISIBLE);
- arrowImg.clearAnimation();
- arrowImg.setVisibility(View.INVISIBLE);
- tipsTxt.setText("正在刷新...");
- lastUpdateTxt.setVisibility(View.VISIBLE);
- break;
- case DONE:
- lastHeaderPadding = -1 * headerHeight;
- header.setPadding(0, lastHeaderPadding, 0, 0);
- header.invalidate();
- headProgress.setVisibility(View.GONE);
- arrowImg.clearAnimation();
- arrowImg.setVisibility(View.VISIBLE);
- tipsTxt.setText("下拉刷新");
- lastUpdateTxt.setVisibility(View.VISIBLE);
- break;
- default:
- break;
- }
- }
- private void onRefresh() {
- new AsyncTask<Void, Void, Void>() {
- protected Void doInBackground(Void... params) {
- try {
- Thread.sleep(2000);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- @Override
- protected void onPostExecute(Void result) {
- onRefreshComplete();
- }
- }.execute(null);
- }
- public void onRefreshComplete() {
- headerState = DONE;
- lastUpdateTxt.setText("最近更新:" + new Date().toLocaleString());
- changeHeaderViewByState();
- }
- //由于OnCreate里面拿不到header的高度所以需要手动计算
- private void measureView(View childView) {
- LayoutParams p = childView.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 height = p.height;
- int childHeightSpec;
- if (height > 0) {
- childHeightSpec = MeasureSpec.makeMeasureSpec(height,
- MeasureSpec.EXACTLY);
- } else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(0,
- MeasureSpec.UNSPECIFIED);
- }
- childView.measure(childWidthSpec, childHeightSpec);
- }
- }<span style="color: rgb(255, 0, 0);">
- </span>