自定义上拉下拉反弹ScrollView

padding式的上下拉反弹,下拉放大顶部图片,松开反弹,上拉显示空白区域,松开反弹.

和现在的淘宝客户端一样下拉时放大顶部图片,并自动回收,费话不多说,上代码:


package com.spider.reader.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;

import com.spider.reader.R;

/**
 * 自定义上拉下拉反弹ScrollView
 * 
 * @author Seal Created on 2014-1-10 上午9:15:26
 * @note padding式的上下拉反弹,下拉放大顶部图片,松开反弹,上拉显示空白区域,松开反弹
 */
public class PullScrollView extends ScrollView {
	private ViewGroup inner;
	View childOne = null;
	private Rect rect;
	private float preY;// 之前的Y坐标的记录
	private float nowY;// 现在的Y坐标的记录
	private float moveY = 0;// 滑动距离
	private boolean isUpRecord = false;// 下拉记录
	private boolean isDownRecord = false;// 上拉记录
	private ImageView image;
	private Context context;
	private Drawable d;
	private String title;
	private final float imageHight = 0;

	public PullScrollView(Context context) {
		super(context);
		this.context = context;
	}

	public PullScrollView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		this.context = context;
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.PullScrollView, defStyle, 0);
		d = a.getDrawable(R.styleable.PullScrollView_pic);
		title = a.getString(R.styleable.PullScrollView_title);
		a.recycle();
	}

	public PullScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.PullScrollView);
		d = a.getDrawable(R.styleable.PullScrollView_pic);
		title = a.getString(R.styleable.PullScrollView_title);
		a.recycle();
	}

	@Override
	protected void onFinishInflate() {
		if (getChildCount() > 0) {
			inner = (ViewGroup) getChildAt(0);
			if (inner.getChildCount() > 0) {
				childOne = inner.getChildAt(0);
			}
			RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
					RelativeLayout.LayoutParams.MATCH_PARENT, (int) imageHight);
			params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
			image = new ImageView(context);
			image.setId(0x10000101);
			if (d != null) {
				image.setBackgroundDrawable(d);
			}
			inner.addView(image, params);
			if (childOne != null) {
				RelativeLayout.LayoutParams oneParams = new RelativeLayout.LayoutParams(
						RelativeLayout.LayoutParams.MATCH_PARENT,
						RelativeLayout.LayoutParams.WRAP_CONTENT);
				oneParams.addRule(RelativeLayout.BELOW, image.getId());
				childOne.setLayoutParams(oneParams);
			}
			rect = new Rect();
			rect.set(inner.getPaddingLeft(), inner.getPaddingTop(),
					inner.getPaddingRight(), inner.getPaddingBottom());
		}
		super.onFinishInflate();
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			nowY = ev.getY();
			record();
			break;
		case MotionEvent.ACTION_MOVE:
			nowY = ev.getY();
			record();
			if (isUpRecord || isDownRecord) {
				moveY = nowY - preY;
			}
			break;
		case MotionEvent.ACTION_UP:
			if (isUpRecord || isDownRecord) {
				startRecorverAnimation();
			}
			break;
		default:
			break;
		}
		if (isUpRecord && moveY > 0) {
			RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
					RelativeLayout.LayoutParams.MATCH_PARENT,
					(int) (imageHight + moveY / 2));
			params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
			image.setLayoutParams(params);
		} else if (isDownRecord && moveY < 0) {
			inner.setPadding(rect.left, rect.top, rect.right,
					(int) (rect.bottom - moveY / 2));
		}
		return super.onTouchEvent(ev);
	}

	private void startRecorverAnimation() {
		Animation transAnimation = null;
		if (inner.getPaddingBottom() > rect.bottom) {
			isDownRecord = false;
			transAnimation = new TranslateAnimation(0, 0,
					-inner.getPaddingBottom(), rect.bottom);
			transAnimation.setDuration(200);
			inner.setAnimation(transAnimation);
			inner.startAnimation(transAnimation);
			inner.setPadding(rect.left, rect.top, rect.right, rect.bottom);
		} else if (image.getHeight() > imageHight) {
			new AsyncTask<String, Float, String>() {

				@Override
				protected String doInBackground(String... params) {
					while (image.getHeight() > imageHight) {
						float distance = image.getHeight() - imageHight;
						int step = 30;// 变化步伐
						distance = distance > step ? distance - step : 0;
						publishProgress(distance);
						try {
							Thread.sleep(3);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					return null;
				}

				@Override
				protected void onProgressUpdate(Float... values) {
					RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
							RelativeLayout.LayoutParams.MATCH_PARENT,
							(int) (imageHight + values[0]));
					params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
					image.setLayoutParams(params);
					super.onProgressUpdate(values);
				}

				protected void onPostExecute(String result) {
					isUpRecord = false;
				};
			}.execute("kaishi");
		}
	}

	private void record() {
		if (!isUpRecord && getScrollY() == 0) {
			preY = nowY;
			isUpRecord = true;
			isDownRecord = false;
		} else if (!isDownRecord
				&& getScrollY() == inner.getMeasuredHeight() - getHeight()) {
			preY = nowY;
			isDownRecord = true;
			isUpRecord = false;
		}
	}
}

 <com.spider.reader.view.PullScrollView
        xmlns:pullscroll="http://schemas.android.com/apk/res/com.spider.reader"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_below="@id/head_layout"
        android:fadingEdge="none"
        pullscroll:pic="@drawable/icon"
        pullscroll:title="testTitle" />
  <declare-styleable name="PullScrollView">
        <attr name="pic" format="reference" />
        <attr name="title" format="string" />
    </declare-styleable>








评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值