仿微信圖片查看器入場退場動畫

引子

看微信朋友圈的時候,當咱們點擊圖片,圖片會從點擊的圖片位置,逐漸放大,移動到正中間。退出圖片查看器的時候,圖片會逐漸變小,移到初始位置。對於用戶來講,這是一種很是好的體驗效果。git

因而,本身手動擼了一個進場退場的動畫。具體參見下圖 github

 

 下面,開始介紹實現原理。微信

原理解析

 先對上面的動畫進行分析:ide

  1. 點擊後,是從新打開了一個 activity,固然也能夠是一個 fragment,均可以。
  2. 圖片是從原始位置逐漸放大移到那個到中間位置的。這個過程都發生在打開後的頁面中。動畫

  3. 再次點擊圖片,退出的時候,先作動畫,在移除原有的acticity.

經過上面的分析,咱們已經知道粗略的技術方案了,接下去就是解決一些細節問題。ui

從第一個頁面打開到第二個頁面,須要傳遞什麼參數?

首先是,圖片的位置信息,只有這樣咱們才能夠將圖片從原始位置逐步放大。下面咱們開始獲取圖片的座標參數:url

   /**
     * 獲取圖片的位置信息
     */
    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 :spa

        // 點擊事件
        View.OnClickListener onClickListener = new View.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 的默認動畫。避免影響圖片的動畫效果。code

如何讓圖片從原始位置動起來?

 在作動畫前,須要作一些準備工做,好比計算可顯示圖片的屏幕寬高,放大係數,移動係數等。blog

/**
     * 計算動畫位移和縮放
     */
    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,圖片查看器中圖片可放大縮小,拖拽等。

相關文章
相關標籤/搜索