仿微信圖片查看器入場退場動畫
阿新 • • 發佈:2019-02-24
要去 block getheight available 新的 坐標 scale epo inf
引子
看微信朋友圈的時候,當我們點擊圖片,圖片會從點擊的圖片位置,逐漸放大,移動到正中間。退出圖片查看器的時候,圖片會逐漸變小,移到初始位置。對於用戶來說,這是一種非常好的體驗效果。
於是,自己手動擼了一個進場退場的動畫。具體參見下圖
下面,開始介紹實現原理。
原理解析
先對上面的動畫進行分析:
- 點擊後,是重新打開了一個 activity,當然也可以是一個 fragment,都可以。
-
圖片是從原始位置逐漸放大移到那個到中間位置的。這個過程都發生在打開後的頁面中。
- 再次點擊圖片,退出的時候,先做動畫,在移除原有的acticity.
通過上面的分析,我們已經知道粗略的技術方案了,接下去就是解決一些細節問題。
從第一個頁面打開到第二個頁面,需要傳遞什麽參數?
首先是,圖片的位置信息,只有這樣我們才可以將圖片從原始位置逐步放大。下面我們開始獲取圖片的坐標參數:
/** * 獲取圖片的位置信息 */ public ArrayList getImagePos(View view) { int[] locat = new int[2]; view.getLocationOnScreen(locat); int width = view.getWidth(); int height = view.getHeight(); ArrayList<Integer> posArr = new ArrayList<>(); posArr.add(locat[0]); posArr.add(locat[0] + width); posArr.add(locat[1]); posArr.add(locat[1] + height); return posArr; }
將圖片的位置信息傳給新的 actvity :
// 點擊事件 View.OnClickListener onClickListener = newView.OnClickListener() { @Override public void onClick(View v) { int pos = mRecyclerView.getChildAdapterPosition(v); Intent intent = new Intent(); intent.setClass(mContext, Main2Activity.class); intent.putIntegerArrayListExtra(POS_ARRAY, getImagePos(v)); intent.putExtra(IMAGE_POS, pos); startActivity(intent); overridePendingTransition(0, 0); } };
註意需要去除原有的 activity 的默認動畫。避免影響圖片的動畫效果。
如何讓圖片從原始位置動起來?
在做動畫前,需要做一些準備工作,比如計算可顯示圖片的屏幕寬高,放大系數,移動系數等。
/** * 計算動畫位移和縮放 */ private void computerAnimationParams() { if (mPosArr.size() != 4) { return; } int screenHigh = mMetrics.heightPixels; int screenWidth = mMetrics.widthPixels; // 計算可用於顯示圖片的屏幕高度 int availableScreenHeight = screenHigh - getStatusBarHeight(); int imageHeight = mPosArr.get(3) - mPosArr.get(2); mOriginWidth = mPosArr.get(1) - mPosArr.get(0); float radioWidth = screenWidth * 1.0f / mOriginWidth; float radioHeight = availableScreenHeight * 1.0f / imageHeight; // 獲取放大系數 mRadio = Math.min(radioHeight, radioWidth); // 計算位移距離,屏幕中心與圖片中心的距離, mTransition[0] = (float) (screenWidth / 2 - (mPosArr.get(0) + (mPosArr.get(1) - mPosArr.get(0)) / 2)); mTransition[1] = (float) ((availableScreenHeight) / 2 - (mPosArr.get(2) - getStatusBarHeight() + (mPosArr.get(3) - mPosArr.get(2)) / 2)); }
具體可以參考上面的代碼,記得要考慮狀態欄對於動畫的影響。計算好了之後,我們得將現有的圖片先設置成原始大小:
/** * 動畫前的準備工作 **/ private void doReadyJob() { // 需要對圖片的寬度進行調整 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(mOriginWidth, FrameLayout.LayoutParams.MATCH_PARENT); params.setMargins(mPosArr.get(0), 0, mPosArr.get(1), 0); mImageView.setLayoutParams(params); }
一切準備就緒後,我們得將圖片從原始位置移動到正中間。下面就是動畫實現細節:
/** * 模擬入場動畫 */ private void showEnterAnim() { final ValueAnimator enterAnimator = ValueAnimator.ofFloat(0f, 1f).setDuration(DURATION_IN); enterAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); enterAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); mImageView.setAlpha(1f); mImageView.setScaleX(1 + (mRadio - 1) * value); mImageView.setScaleY(1 + (mRadio - 1) * value); mImageView.setTranslationX(mTransition[0] * value); mImageView.setTranslationY(-mTransition[1] * (1f - value)); mImageView.invalidate(); } }); enterAnimator.start(); }
這裏我們通過 ValueAnimator 來控制更新動畫進度。到這裏,圖片的進場動畫就完成了。
對於退場動畫,原理是一樣的:
/** * 模擬退場動畫 */ private void showOutAnim() { final ValueAnimator exitAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(DURATION_IN); mImageView.setAlpha(1f); exitAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); exitAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); mImageView.setScaleX((mRadio - 1) * value + 1); mImageView.setScaleY((mRadio - 1) * value + 1); mImageView.setTranslationX(mTransition[0] * value); mImageView.setTranslationY(-mTransition[1] * (1f - value)); } }); exitAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { quitActivityWithoutAnimation(); } }); exitAnimator.start(); }
到這裏,動畫的主要原理已經剖析完成。
源碼: https://github.com/huanshen/PictureViewer
目前這個比較簡單,真的在項目實現起來的時候,代碼量還是蠻多的,並且考慮的也要更多。
比如,你還得傳遞圖片的 url,圖片查看器中圖片可放大縮小,拖拽等。
仿微信圖片查看器入場退場動畫