ScrollView 实现下拉刷新(二)

在 ScrollView 实现下拉刷新(一)的基础上再做封装,使得更好的进行复用。

package edu.jxau.tboing.layout;

import java.util.Date;

import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
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.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
import edu.jxau.tboing.jwassistant.R;


public class DropLayout extends LinearLayout {
	
	private ScrollView sc;
	private LayoutInflater inflater;
	private LinearLayout header;
	private ImageView arrowImg;
	private ProgressBar headProgress;
	private TextView lastUpdateTxt;
	private TextView tipsTxt;
	private RotateAnimation tipsAnimation;
	private RotateAnimation reverseAnimation;
	private int headerHeight;	//头高度
	private int lastHeaderPadding; //最后一次调用Move Header的Padding
	private boolean isBack; //从Release 转到 pull
	private int headerState = DONE;
	private RefreshCallBack callBack;
	private LinearLayout subLayout;
	
	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;
	
	
	public DropLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
	
	private void init(Context context) {
		inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		sc = new ScrollView(context);
		sc.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		//由于ScrollView 只允许有一个ChildView所以再用LinearLayout来做容器
		subLayout = new LinearLayout(context);
		subLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
		subLayout.setOrientation(VERTICAL);
		sc.addView(subLayout);
		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();
		this.addView(header,0);
		this.addView(sc,1);
		
		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;
				}
			}
		});
	}
	
	@Override
	public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
		//读取XML中的默认给 -1 自己添加的为0 和 1
		if(index == -1) {
			subLayout.addView(child, params);
			return ;
		}
		super.addView(child, index, params);
	}
	
	public void setRefreshCallBack(RefreshCallBack callBack) {
		this.callBack = callBack;
	}
	
	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 RefreshAsyncTask().execute();
	}
	
	private class RefreshAsyncTask extends AsyncTask<Void, Void, Void> {
		protected Void doInBackground(Void... params) {
			if(callBack != null) {
				callBack.doInBackground();
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			onRefreshComplete();
			if(callBack != null) {
				callBack.complete();
			}
		}
	}
	public interface RefreshCallBack {
		public void doInBackground();
		public void complete();
	}
	@SuppressWarnings("deprecation")
	public void onRefreshComplete() {
		headerState = DONE;
		lastUpdateTxt.setText("最近更新:" + new Date().toLocaleString());
		changeHeaderViewByState();
	}
	//由于OnCreate里面拿不到header的高度所以需要手动计算
	private void measureView(View childView) {
		android.view.ViewGroup.LayoutParams p = childView.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 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);
	}
}


在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:orientation="vertical" >

    <edu.jxau.tboing.layout.DropLayout
        android:id="@+id/dropView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

       
    </edu.jxau.tboing.layout.DropLayout>

</LinearLayout>

然后记得带上图片和header的XML :

<?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>

这样就大功告成了,这样就能比较好的进行复用了。

这样比ListView的下拉刷新更有优势。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值