ListView的headerView下拉刷新PullToZoomInListView分析



listView 的headerView下拉刷新比较流行,比如商品列表中对品牌的介绍可以用到这个功能,体验感受了下PullToZoomInListView,

感觉比较好的效果,就拿来分析下。


PullToZoomInListView 是自定义了一个ListView,headerVIew的图片支持缩放,效果比较有美感,动画也比较流畅,是一个比较好的

项目。



其实PullToZoomListView的实现原理很简单

主要是在case MotionEvent.ACTION_MOVE:代码段中判断向下滑动的偏移量,根据这个来改变listview headerView内容

区域的高度,并且在手指放开的那一刻,停止缩放,启用一个动画来使HeaderView平滑的恢复到放大之前的状态。

1、首先初始化画布局init(Context paramContext),通过setHeaderViewSize(i, (int) (9.0F * (i / 16.0F)))设置header图片的大小,启动ScalingRunnalable线程;

2、初始化完成后,注册一个OnScrollListener监听,当滚动之后可以恢复到初始化的状态

public void onScroll(AbsListView paramAbsListView, int paramInt1,
			int paramInt2, int paramInt3) {
		Log.d("mmm", "onScroll");
		float f = this.mHeaderHeight - this.mHeaderContainer.getBottom();
		Log.d("mmm", "f|" + f);
		if ((f > 0.0F) && (f < this.mHeaderHeight)) {
			Log.d("mmm", "1");
			int i = (int) (0.65D * f);
			this.mHeaderImage.scrollTo(0, -i);
		} else if (this.mHeaderImage.getScrollY() != 0) {
			Log.d("mmm", "2");
			this.mHeaderImage.scrollTo(0, 0);
		}
		if (this.mOnScrollListener != null) {
			this.mOnScrollListener.onScroll(paramAbsListView, paramInt1,
					paramInt2, paramInt3);
		}
	}


3、拉动时候缩放,主要是在 MotionEvent.ACTION_MOVE:代码段中判断向下滑动的偏移量,

this.mHeaderContainer.getBottom() >= this.mHeaderHeight,图片下移,放大图片


case MotionEvent.ACTION_MOVE:
			Log.d("mmm", "mActivePointerId" + mActivePointerId);
			int j = paramMotionEvent.findPointerIndex(this.mActivePointerId);
			if (j == -1) {
				Log.e("PullToZoomListView", "Invalid pointerId="
						+ this.mActivePointerId + " in onTouchEvent");
			} else {
				if (this.mLastMotionY == -1.0F)
					this.mLastMotionY = paramMotionEvent.getY(j);
				if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) {
					ViewGroup.LayoutParams localLayoutParams = this.mHeaderContainer
							.getLayoutParams();
					float f = ((paramMotionEvent.getY(j) - this.mLastMotionY + this.mHeaderContainer
							.getBottom()) / this.mHeaderHeight - this.mLastScale)
							/ 2.0F + this.mLastScale;
					if ((this.mLastScale <= 1.0D) && (f < this.mLastScale)) {
						localLayoutParams.height = this.mHeaderHeight;
						this.mHeaderContainer
								.setLayoutParams(localLayoutParams);
						return super.onTouchEvent(paramMotionEvent);
					}
					this.mLastScale = Math.min(Math.max(f, 1.0F),
							this.mMaxScale);
					localLayoutParams.height = ((int) (this.mHeaderHeight * this.mLastScale));
					if (localLayoutParams.height < this.mScreenHeight)
						this.mHeaderContainer
								.setLayoutParams(localLayoutParams);
					this.mLastMotionY = paramMotionEvent.getY(j);
					return true;
				}
				this.mLastMotionY = paramMotionEvent.getY(j);
			}
			break;

4、在放开手指的时候,开启动画恢复到原来的位置,线程中循环调用改变imageview的高度,知道满足条件退出循环。

public void run() {
			float f2;
			ViewGroup.LayoutParams localLayoutParams;
			if ((!this.mIsFinished) && (this.mScale > 1.0D)) {
				float f1 = ((float) SystemClock.currentThreadTimeMillis() - (float) this.mStartTime)
						/ (float) this.mDuration;
				f2 = this.mScale - (this.mScale - 1.0F)
						* PullToZoomListView.sInterpolator.getInterpolation(f1);
				localLayoutParams = PullToZoomListView.this.mHeaderContainer
						.getLayoutParams();
				if (f2 > 1.0F) {
					Log.d("mmm", "f2>1.0");
					localLayoutParams.height = PullToZoomListView.this.mHeaderHeight;
					;
					localLayoutParams.height = ((int) (f2 * PullToZoomListView.this.mHeaderHeight));
					PullToZoomListView.this.mHeaderContainer
							.setLayoutParams(localLayoutParams);
					PullToZoomListView.this.post(this);
					return;
				}
				this.mIsFinished = true;
			}
		}

难点不在于如何改变mHeaderContainer的高度吧,难在如何让一个View按一定的时间曲线改变属性,这其实是属性动画该做的事,但是这里没有用属性动画,显然作者对View的动画很熟悉,我觉得这里作者用自己的方法实现了属性动画, ScalingRunnalable在startAnimation中调用了PullToZoomListView.this.post(this);不懂得可以搜索View.post(Runnable),post调用ScalingRunnalable的run方法,而ScalingRunnalable run方法中再次调用了post,就这样不断的更新UI,直到达到一定的条件退出这个循环(这里这个条件是if((!this.mIsFinished) && (this.mScale > 1.0D))),这里的关键点是每次执行run的时候mHeaderContainer的高度究竟该变化多少,

1
2
f2 =this.mScale - (this.mScale -1.0F)
                    * PullToZoomListView.sInterpolator.getInterpolation(f1);

中PullToZoomListView.sInterpolator.getInterpolation(f1)给了我们答案

	public float getInterpolation(float paramAnonymousFloat) {
			float f = paramAnonymousFloat - 1.0F;
			return 1.0F + f * (f * (f * (f * f)));
		}

这个方法其实是一个指数函数,中学的时候学过y=1+f^4;也就是动画Intepolater速度变化是以这个指数增长。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值