zoukankan      html  css  js  c++  java
  • Android PullToZoomListView实现放大回弹效果

    版本号:1.0 
    日期:2014.8.4
    版权:© 2014 kince 转载注明出处

      之前看过一篇文章,链接是:能够下拉缩放HeaderView的ListView:PullToZoomInListView

    说的就是PullToZoomListView。只是这篇文章有个地方须要勘误,就是PullToZoomListView这个控件尽管是github上一个开源项目。只是最美应用并非使用这个开源项目,而是这个开源项目反编译了最美应用的代码。

      可是,它这个代码是有问题的,当手指在屏幕上滑动的时候会引发onItemClick事件。

    看了一下它的代码。发现是由于在onTouchEvent()方法中的MotionEvent.ACTION_MOVE中return true了,这样就会消费这个事件。所以导致了onItemClick事件。

    之后我也反编译了一下最美应用,看了一下这个控件的实现,发现还有其它问题,比方少了一些变量,没有重写onInterceptTouchEvent()方法等。因此我又自己动手把这个控件丰富了一下。使其能够最大限度的接近原始代码。并且可正常使用。改动后代码例如以下:

    package com.kince.android.pulltozoomlistview;
    
    import android.app.Activity;
    import android.content.Context;
    import android.os.SystemClock;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.ViewGroup;
    import android.view.animation.Interpolator;
    import android.widget.AbsListView;
    import android.widget.FrameLayout;
    import android.widget.ImageView;
    import android.widget.ListView;
    
    public class PullToZoomListView extends ListView implements
    		AbsListView.OnScrollListener {
    
    	private static final int INVALID_VALUE = -1;
    	private static final String TAG = "PullToZoomListView";
    	private static final Interpolator sInterpolator = new Interpolator() {
    		public float getInterpolation(float paramAnonymousFloat) {
    			float f = paramAnonymousFloat - 1.0F;
    			return 1.0F + f * (f * (f * (f * f)));
    		}
    	};
    	int mActivePointerId = -1;
    	private FrameLayout mHeaderContainer;
    	private int mHeaderHeight;
    	private ImageView mHeaderImage;
    	float mLastMotionY = -1.0F;
    	float mLastScale = -1.0F;
    	float mMaxScale = -1.0F;
    	private AbsListView.OnScrollListener mOnScrollListener;
    	private ScalingRunnalable mScalingRunnalable;
    	private int mScreenHeight;
    	private ImageView mShadow;
    
    	private boolean mScrollable = true;
    	private boolean mShowHeaderImage = true;
    	private boolean mZoomable = true;
    
    	public PullToZoomListView(Context paramContext) {
    		super(paramContext);
    		init(paramContext);
    	}
    
    	public PullToZoomListView(Context paramContext,
    			AttributeSet paramAttributeSet) {
    		super(paramContext, paramAttributeSet);
    		init(paramContext);
    	}
    
    	public PullToZoomListView(Context paramContext,
    			AttributeSet paramAttributeSet, int paramInt) {
    		super(paramContext, paramAttributeSet, paramInt);
    		init(paramContext);
    	}
    
    	private void endScraling() {
    		if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight)
    			Log.d("mmm", "endScraling");
    		this.mScalingRunnalable.startAnimation(200L);
    	}
    
    	private void init(Context paramContext) {
    		DisplayMetrics localDisplayMetrics = new DisplayMetrics();
    		((Activity) paramContext).getWindowManager().getDefaultDisplay()
    				.getMetrics(localDisplayMetrics);
    		this.mScreenHeight = localDisplayMetrics.heightPixels;
    		this.mHeaderContainer = new FrameLayout(paramContext);
    		this.mHeaderImage = new ImageView(paramContext);
    		int i = localDisplayMetrics.widthPixels;
    		setHeaderViewSize(i, (int) (9.0F * (i / 16.0F)));
    		this.mShadow = new ImageView(paramContext);
    		FrameLayout.LayoutParams localLayoutParams = new FrameLayout.LayoutParams(
    				-1, -2);
    		localLayoutParams.gravity = 80;
    		this.mShadow.setLayoutParams(localLayoutParams);
    		this.mHeaderContainer.addView(this.mHeaderImage);
    		this.mHeaderContainer.addView(this.mShadow);
    		addHeaderView(this.mHeaderContainer);
    		this.mScalingRunnalable = new ScalingRunnalable();
    		super.setOnScrollListener(this);
    	}
    
    	private void onSecondaryPointerUp(MotionEvent paramMotionEvent) {
    		int i = (paramMotionEvent.getAction()) >> 8;
    		Log.d("onSecondaryPointerUp", i + "");
    		if (paramMotionEvent.getPointerId(i) == this.mActivePointerId)
    			if (i != 0) {
    				this.mLastMotionY = paramMotionEvent.getY(1);
    				this.mActivePointerId = paramMotionEvent.getPointerId(0);
    				return;
    			}
    	}
    
    	private void reset() {
    		this.mActivePointerId = -1;
    		this.mLastMotionY = -1.0F;
    		this.mMaxScale = -1.0F;
    		this.mLastScale = -1.0F;
    	}
    
    	public ImageView getHeaderView() {
    		return this.mHeaderImage;
    	}
    
    	public void hideHeaderImage() {
    		this.mShowHeaderImage = false;
    		this.mZoomable = false;
    		this.mScrollable = false;
    		removeHeaderView(this.mHeaderContainer);
    	}
    
    	public boolean isScrollable() {
    		return this.mScrollable;
    	}
    
    	public boolean isZoomable() {
    		return this.mZoomable;
    	}
    
    	public boolean onInterceptTouchEvent(MotionEvent paramMotionEvent) {
    		if (!this.mZoomable) {
    			return super.onInterceptTouchEvent(paramMotionEvent);
    		}
    		switch (paramMotionEvent.getAction() & MotionEvent.ACTION_MASK) {
    		case MotionEvent.ACTION_DOWN:
    
    			this.mActivePointerId = paramMotionEvent.getPointerId(0);
    			this.mMaxScale = (this.mScreenHeight / this.mHeaderHeight);
    			break;
    
    		case MotionEvent.ACTION_UP:
    			reset();
    			break;
    
    		case MotionEvent.ACTION_POINTER_DOWN:
    			this.mActivePointerId = paramMotionEvent
    					.getPointerId(paramMotionEvent.getActionIndex());
    			break;
    
    		case MotionEvent.ACTION_POINTER_UP:
    			onSecondaryPointerUp(paramMotionEvent);
    			break;
    		}
    		return super.onInterceptTouchEvent(paramMotionEvent);
    	}
    
    	protected void onLayout(boolean paramBoolean, int paramInt1, int paramInt2,
    			int paramInt3, int paramInt4) {
    		super.onLayout(paramBoolean, paramInt1, paramInt2, paramInt3, paramInt4);
    		if (this.mHeaderHeight == 0)
    			this.mHeaderHeight = this.mHeaderContainer.getHeight();
    	}
    
    	@Override
    	public void onScroll(AbsListView paramAbsListView, int paramInt1,
    			int paramInt2, int paramInt3) {
    		if (this.mScrollable) {
    			Log.d(TAG, "onScroll");
    			float f = this.mHeaderHeight - this.mHeaderContainer.getBottom();
    			Log.d("onScroll", "f|" + f);
    			if ((f > 0.0F) && (f < this.mHeaderHeight)) {
    				Log.d("onScroll", "1");
    				int i = (int) (0.65D * f);
    				this.mHeaderImage.scrollTo(0, -i);
    			} else if (this.mHeaderImage.getScrollY() != 0) {
    				Log.d("onScroll", "2");
    				this.mHeaderImage.scrollTo(0, 0);
    			}
    		}
    
    		if (this.mOnScrollListener != null) {
    			this.mOnScrollListener.onScroll(paramAbsListView, paramInt1,
    					paramInt2, paramInt3);
    		}
    	}
    
    	public void onScrollStateChanged(AbsListView paramAbsListView, int paramInt) {
    		if (this.mOnScrollListener != null)
    			this.mOnScrollListener.onScrollStateChanged(paramAbsListView,
    					paramInt);
    	}
    
    	public boolean onTouchEvent(MotionEvent ev) {
    
    		Log.d(TAG, "" + (0xFF & ev.getAction()));
    		if (!this.mZoomable) {
    			Log.i("zoom", "zoom");
    			return super.onTouchEvent(ev);
    		}
    		switch (ev.getAction() & MotionEvent.ACTION_MASK) {
    		case MotionEvent.ACTION_OUTSIDE:
    		case MotionEvent.ACTION_DOWN:
    			if (!this.mScalingRunnalable.mIsFinished) {
    				this.mScalingRunnalable.abortAnimation();
    			}
    			this.mLastMotionY = ev.getY();
    			this.mActivePointerId = ev.getPointerId(0);
    			this.mMaxScale = (this.mScreenHeight / this.mHeaderHeight);
    			this.mLastScale = (this.mHeaderContainer.getBottom() / this.mHeaderHeight);
    			break;
    		case MotionEvent.ACTION_MOVE:
    			Log.d("onTouchEvent", "mActivePointerId" + mActivePointerId);
    			int j = ev.findPointerIndex(this.mActivePointerId);
    			if (j == -1) {
    				Log.e("PullToZoomListView", "Invalid pointerId="
    						+ this.mActivePointerId + " in onTouchEvent");
    			} else {
    				if (this.mLastMotionY == -1.0F)
    					this.mLastMotionY = ev.getY(j);
    				if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) {
    					ViewGroup.LayoutParams localLayoutParams = this.mHeaderContainer
    							.getLayoutParams();
    					float f = ((ev.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);
    					}
    					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 = ev.getY(j);
    				}
    				this.mLastMotionY = ev.getY(j);
    			}
    			break;
    		case MotionEvent.ACTION_UP:
    			reset();
    			endScraling();
    			break;
    		case MotionEvent.ACTION_CANCEL:
    
    			break;
    		case MotionEvent.ACTION_POINTER_DOWN:
    			int i = ev.getActionIndex();
    			this.mLastMotionY = ev.getY(i);
    			this.mActivePointerId = ev.getPointerId(i);
    			break;
    		case MotionEvent.ACTION_POINTER_UP:
    			onSecondaryPointerUp(ev);
    			this.mLastMotionY = ev.getY(ev
    					.findPointerIndex(this.mActivePointerId));
    			break;
    		}
    		return super.onTouchEvent(ev);
    	}
    
    	public void setHeaderViewSize(int paramInt1, int paramInt2) {
    		if (!this.mShowHeaderImage) {
    			return;
    		}
    		Object localObject = this.mHeaderContainer.getLayoutParams();
    		if (localObject == null)
    			localObject = new AbsListView.LayoutParams(paramInt1, paramInt2);
    		((ViewGroup.LayoutParams) localObject).width = paramInt1;
    		((ViewGroup.LayoutParams) localObject).height = paramInt2;
    		this.mHeaderContainer
    				.setLayoutParams((ViewGroup.LayoutParams) localObject);
    		this.mHeaderHeight = paramInt2;
    	}
    
    	public void setOnScrollListener(
    			AbsListView.OnScrollListener paramOnScrollListener) {
    		this.mOnScrollListener = paramOnScrollListener;
    	}
    
    	public void setScrollable(boolean paramBoolean) {
    		if (!this.mShowHeaderImage) {
    			return;
    		}
    		this.mScrollable = paramBoolean;
    	}
    
    	public void setShadow(int paramInt) {
    		if (!this.mShowHeaderImage) {
    			return;
    		}
    		this.mShadow.setBackgroundResource(paramInt);
    	}
    
    	public void setZoomable(boolean paramBoolean) {
    		if (!this.mShowHeaderImage) {
    			return;
    		}
    		this.mZoomable = paramBoolean;
    	}
    
    	class ScalingRunnalable implements Runnable {
    		long mDuration;
    		boolean mIsFinished = true;
    		float mScale;
    		long mStartTime;
    
    		ScalingRunnalable() {
    		}
    
    		public void abortAnimation() {
    			this.mIsFinished = true;
    		}
    
    		public boolean isFinished() {
    			return this.mIsFinished;
    		}
    
    		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;
    			}
    		}
    
    		public void startAnimation(long paramLong) {
    			this.mStartTime = SystemClock.currentThreadTimeMillis();
    			this.mDuration = paramLong;
    			this.mScale = ((float) (PullToZoomListView.this.mHeaderContainer
    					.getBottom()) / PullToZoomListView.this.mHeaderHeight);
    			this.mIsFinished = false;
    			PullToZoomListView.this.post(this);
    		}
    	}
    }
    
      关于这个控件的实现原理能够自行參考上面链接的文章,里面已经有较为仔细的解说,此处不再赘述。

    实现的效果就是以下这样:

      github链接:https://github.com/wangjinyu501/PullToZoomListView/,假设您发现了不论什么问题。能够在文章以下留言,我会第一时间处理。欢迎交流。


  • 相关阅读:
    使用闭包的注意点
    JS中的回收机制
    jQuery选择器之样式
    PNRPC 2017-2018 Gym101615I
    Verilog碎碎念
    Codeforces 420D. Cup Trick
    AGC017C. Snuke and Spells
    XVII Open Cup named after E.V. Pankratiev. GP of Tatarstan B. White Triangle
    SPOJ TETRIS2D
    AGC017B. Moderate Differences
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/6700780.html
Copyright © 2011-2022 走看看