2015年6月23日 星期二

[擒猿密技篇] Android 利用 ImageButton 和 ImageView 實現點擊以縮放圖片的動畫效果

看到標題怕了吧!直接來

首先宣告 Layout 文件如下:
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageButton
        android:id="@+id/imgBtn"
        android:layout_width="150dp"
        android:layout_height="100dp"
        android:layout_alignParentRight="true"
        android:scaleType="centerCrop"/>

    <ImageView
        android:id="@+id/imgBig"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible" />
</RelativeLayout>
很簡單的解釋就是一個 container 下有一個 ImageButton 和一個 ImageView,ImageButton 裡放的是縮圖,點下去後,大圖的 ImageView 才會出現。

程式中的寫法如下:
private ImageButton mImgBtn;
private ImageView mImgBig;
private Animator mCurrentAnimator;

.....

final RelativeLayout layout = (RelativeLayout) View.inflate(
        getActivity(), R.layout.container, null);
mImgBtn = (ImageButton) layout.findViewById(R.id.imgBtn);
mImgBig = (ImageView) layout.findViewById(R.id.imgBig);

mImgBtn.setImageDrawable(Drawable.createFromPath(img_path));
mImgBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        enlargeImage(mImgBtn, img_path, mImgBig, layout);
    }
});

enlargeImage 的寫法是精隨所在:
private void enlargeImage(final View thumbView,
                          String image_path,
                          final ImageView imgBig,
                          RelativeLayout container) {

    // 先清掉原本的動畫
    if (mCurrentAnimator != null) {
        mCurrentAnimator.cancel();
    }

    // 指定 Image 給 ImageView
    imgBig.setImageDrawable(Drawable.createFromPath(image_path));

    // 計算 imgBig 動畫開始和結束的範圍
    final Rect startBounds = new Rect();
    final Rect finalBounds = new Rect();
    final Point globalOffset = new Point();

    thumbView.getGlobalVisibleRect(startBounds);
    container.getGlobalVisibleRect(finalBounds, globalOffset);
    startBounds.offset(-globalOffset.x, -globalOffset.y);
    finalBounds.offset(-globalOffset.x, -globalOffset.y);

    float startScale;
    if ((float) finalBounds.width() / finalBounds.height()
          > (float) startBounds.width() / startBounds.height()) {
        // Extend start bounds horizontally
        startScale = (float) startBounds.height()
                                 / finalBounds.height();
        float startWidth = startScale * finalBounds.width();
        float deltaWidth = (startWidth - startBounds.width())
                                 / 2;
        startBounds.left -= deltaWidth;
        startBounds.right += deltaWidth;
    } else {
        // Extend start bounds vertically
        startScale = (float) startBounds.width()
                                 / finalBounds.width();
        float startHeight = startScale * finalBounds.height();
        float deltaHeight = (startHeight - startBounds.height())
                   / 2;
        startBounds.top -= deltaHeight;
        startBounds.bottom += deltaHeight;
    }

  // 隱藏縮圖並顯示大圖
    thumbView.setAlpha(0f);
    imgBig.setVisibility(View.VISIBLE);

    // 設定大圖縮放的軸度
    imgBig.setPivotX(0f);
    imgBig.setPivotY(0f);

    // 設定並撥放圖片放大動畫
    AnimatorSet set = new AnimatorSet();
    set
        .play(ObjectAnimator.ofFloat(imgBig, View.X,
                startBounds.left, finalBounds.left))
        .with(ObjectAnimator.ofFloat(imgBig, View.Y,
                startBounds.top, finalBounds.top))
        .with(ObjectAnimator.ofFloat(imgBig, View.SCALE_X,
                startScale, 1f)).with(
                ObjectAnimator.ofFloat(imgBig,
                View.SCALE_Y, startScale, 1f));
    set.setDuration(500);
    set.setInterpolator(new DecelerateInterpolator());
    set.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            mCurrentAnimator = null;
        }

        @Override
        public void onAnimationCancel(Animator animation) {
            mCurrentAnimator = null;
        }
    });
    set.start();
    mCurrentAnimator = set;

    // 實現再次點擊後縮回原圖並隱藏大圖
    final float startScaleFinal = startScale;
        imgBig.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (mCurrentAnimator != null) {
                mCurrentAnimator.cancel();
            }

            // 設定播放圖片縮小動畫
            AnimatorSet set = new AnimatorSet();
            set.play(ObjectAnimator.ofFloat(imgBig,
                    View.X, startBounds.left))
                .with(ObjectAnimator.ofFloat(imgBig,
                    View.Y,startBounds.top))
                .with(ObjectAnimator.ofFloat(imgBig,
                    View.SCALE_X, startScaleFinal))
                .with(ObjectAnimator.ofFloat(imgBig,
                    View.SCALE_Y, startScaleFinal));
                set.setDuration(500);
                set.setInterpolator(new DecelerateInterpolator());
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        thumbView.setAlpha(1f);
                        imgBig.setVisibility(View.GONE);
                        mCurrentAnimator = null;
                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {
                        thumbView.setAlpha(1f);
                        imgBig.setVisibility(View.GONE);
                        mCurrentAnimator = null;
                    }
                });
            set.start();
            mCurrentAnimator = set;
        }
    });
}

幹你娘好難喔。

參考文件: http://developer.android.com/training/animation/zoom.html#animate

沒有留言:

張貼留言