9.視差特效、回彈動畫、overScrollBy


視差特效 
應用場景: 微信朋友圈, QQ空間, 微博個人展示,向下拉出,松開回彈
功能實現:
> 1. 重寫overScrollBy

> 2. 松手之后執行動畫, 類型估值器

activity_main
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity" >
        <com.itheima.parallaxdemo.ui.MyListView
            android:id="@+id/lv"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </RelativeLayout>
view_header
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <ImageView
            android:id="@+id/iv"
            android:layout_width="match_parent"
            android:layout_height="160dp"
            android:scaleType="centerCrop"
            android:src="@drawable/parallax_img" />
    </LinearLayout>
MyListView
  1. /**
     * 視差特效ListView
     * overScrollBy
     * @author poplar
     *
     */
    public class MyListView extends ListView {
    	private static final String TAG = "TAG";
    	private int mOriginalHeight;
    	private int drawableHeight;
    	private ImageView mImage;
    	public MyListView(Context context, AttributeSet attrs, int defStyle) {
    		super(context, attrs, defStyle);
    	}
    	public MyListView(Context context, AttributeSet attrs) {
    		super(context, attrs);
    	}
    	public MyListView(Context context) {
    		super(context);
    	}
    	
    	/**
    	 * 設置ImageView圖片, 拿到引用
    	 * @param mImage
    	 */
    	public void setParallaxImage(ImageView mImage) {
    		this.mImage = mImage;
    		mOriginalHeight = mImage.getHeight(); // 160
    		drawableHeight = mImage.getDrawable().getIntrinsicHeight(); // 488,圖片的高,而不是顯示的高
    		
    		Log.d(TAG, "height: " + mOriginalHeight + " drawableHeight: " + drawableHeight);
    	}
    	
    	@Override
    	protected boolean overScrollBy(int deltaX, int deltaY, 
    			int scrollX, int scrollY, int scrollRangeX, int scrollRangeY,
    			int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
    		// deltaY : 豎直方向的瞬時偏移量 / 變化量 dx   頂部到頭下拉為-, 底部到頭上拉為+
    		// scrollY : 豎直方向的偏移量 / 變化量
    		// scrollRangeY : 豎直方向滑動的范圍
    		// maxOverScrollY : 豎直方向最大滑動范圍
    		// isTouchEvent : 是否是手指觸摸滑動, true為手指, false為慣性
    		
    		Log.d(TAG, "deltaY: " +deltaY + " scrollY: " + scrollY + " scrollRangeY: " + scrollRangeY
    				+ " maxOverScrollY: " + maxOverScrollY + " isTouchEvent: " + isTouchEvent);
    		
    		// 手指拉動 並且 是下拉
    		if(isTouchEvent && deltaY < 0){
    			// 把拉動的瞬時變化量的絕對值交給Header, 就可以實現放大效果
    			if(mImage.getHeight() <= drawableHeight){
    				int newHeight = (int) (mImage.getHeight() + Math.abs(deltaY / 3.0f));
    			
    				// 高度不超出圖片最大高度時,才讓其生效
    				mImage.getLayoutParams().height = newHeight;
    				mImage.requestLayout();
    			}
    		}
    		
    		return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
    				scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
    	}
    	
    	@Override
    	public boolean onTouchEvent(MotionEvent ev) {
    		
    		switch (ev.getAction()) {
    			case MotionEvent.ACTION_UP:
    				// 執行回彈動畫, 方式一: 屬性動畫\值動畫
    				// 從當前高度mImage.getHeight(), 執行動畫到原始高度mOriginalHeight
    				final int startHeight = mImage.getHeight();
    				final int endHeight = mOriginalHeight;
    				
    //				valueAnimator(startHeight, endHeight);
    				// 執行回彈動畫, 方式二: 自定義Animation
    				ResetAnimation animation = new ResetAnimation(mImage, startHeight, endHeight);
    				startAnimation(animation);
    				
    				break;
    		}
    		return super.onTouchEvent(ev);
    	}
    	private void valueAnimator(final int startHeight, final int endHeight) {
    		ValueAnimator mValueAnim = ValueAnimator.ofInt(1);//不起作用,寫幾都行
    		mValueAnim.addUpdateListener(new AnimatorUpdateListener() {
    			
    			@Override
    			public void onAnimationUpdate(ValueAnimator mAnim) {
    				float fraction = mAnim.getAnimatedFraction();
    				// percent 0.0 -> 1.0
    				Log.d(TAG, "fraction: " +fraction);
    				Integer newHeight = evaluate(fraction, startHeight, endHeight);//固值器
    				mImage.getLayoutParams().height = newHeight;//設置imageview高度
    				mImage.requestLayout();
    			}
    		});
    		
    		mValueAnim.setInterpolator(new OvershootInterpolator());
    		mValueAnim.setDuration(500);
    		mValueAnim.start();
    	}
    	
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            int startInt = startValue;
            return (int)(startInt + fraction * (endValue - startInt));
        }
    	
    	
    }
ResetAnimation
  1. public class ResetAnimation extends Animation {
    	private final ImageView mImage;
    	private final int startHeight;
    	private final int endHeight;
    	public ResetAnimation(ImageView mImage, int startHeight, int endHeight) {
    		this.mImage = mImage;
    		this.startHeight = startHeight;
    		this.endHeight = endHeight;
    		
    		setInterpolator(new OvershootInterpolator());
    		//設置動畫執行時長
    		setDuration(500);
    	}
    	@Override
    	protected void applyTransformation(float interpolatedTime, Transformation t) {
    		// interpolatedTime 0.0f -> 1.0f
    		
    		Integer newHeight = evaluate(interpolatedTime, startHeight, endHeight);
    		mImage.getLayoutParams().height = newHeight;//設置imageview高
    		mImage.requestLayout();
    		
    		super.applyTransformation(interpolatedTime, t);
    	}
    	
    	
        /**
         * 類型估值器
         * @param fraction
         * @param startValue
         * @param endValue
         * @return
         */
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            int startInt = startValue;
            return (int)(startInt + fraction * (endValue - startInt));
        }
    	
    	
    	
    }
    

     

  2.   MainActivity

  3. public class MainActivity extends Activity {
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		
    		
    		final MyListView mListView = (MyListView) findViewById(R.id.lv);
    		mListView.setOverScrollMode(View.OVER_SCROLL_NEVER);
    		// 加Header
    		final View mHeaderView = View.inflate(MainActivity.this, R.layout.view_header, null);
    		final ImageView mImage = (ImageView) mHeaderView.findViewById(R.id.iv);
    		mListView.addHeaderView(mHeaderView);
    		
    		mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    			
    			@Override
    			public void onGlobalLayout() {
    				// 當布局填充結束之后, 此方法會被調用
    				mListView.setParallaxImage(mImage);
    				
    				mHeaderView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
    			}
    		});
    		
    		// 填充數據
    		mListView.setAdapter(new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, Cheeses.NAMES));
    		
    	}
    }
    

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM