zoom動畫,實現圖片點擊預覽效果,zoom預覽
參考:https://developer.android.google.cn/training/animation/zoom.html
1.建立Views
下面的布局包括了你想要zoom的大版本和小版本的view。
1.ImageButton是小版本的,能點擊的,點擊後顯示大版本的ImageView。
2.ImageView是大版本的,可以顯示ImageButton點擊後的樣式。
3.ImageView一開始是不可見的(invisible),當ImageButton點擊後,它會實現zoom動畫,就像從ImageButton上擴大顯示出來。
1 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:id="@+id/container" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 6 <LinearLayout android:layout_width="match_parent" 7 android:layout_height="wrap_content" 8 android:orientation="vertical" 9 android:padding="16dp">10 11 <ImageButton12 android:id="@+id/thumb_button_1"13 android:layout_width="100dp"14 android:layout_height="75dp"15 android:layout_marginRight="1dp"16 android:src="@drawable/thumb1"17 android:scaleType="centerCrop"18 android:contentDescription="@string/description_image_1" />19 20 </LinearLayout>21 22 <!-- 這個不可見的ImageView持有上面的ImageButton zoom後的圖片版本。23 動畫沒有發生之前,它佔據了整個螢幕。動畫開始,這個View從上面24 ImageButton的範圍變化到他自己最終的範圍。25 -->26 27 <ImageView28 android:id="@+id/expanded_image"29 android:layout_width="match_parent"30 android:layout_height="match_parent"31 android:visibility="invisible"32 android:contentDescription="@string/description_zoom_touch_close" />33 34 </FrameLayout>
2.設定zoom動畫
在ImageButton上設定點擊事件,執行zoom動畫
1 public class ZoomActivity extends FragmentActivity { 2 // 儲存下當前動畫類,以便可以隨時結束動畫 3 private Animator mCurrentAnimator; 4 5 //系統的短時間長度動畫期間(單位ms) 6 // 對於不易察覺的動畫或者頻繁發生的動畫 7 // 這個動畫期間是最理想的 8 private int mShortAnimationDuration; 9 10 @Override11 protected void onCreate(Bundle savedInstanceState) {12 super.onCreate(savedInstanceState);13 setContentView(R.layout.activity_zoom);14 15 // 給ImageButton設定點擊事件16 final View thumb1View = findViewById(R.id.thumb_button_1);17 thumb1View.setOnClickListener(new View.OnClickListener() {18 @Override19 public void onClick(View view) {20 //執行zoom動畫方法21 zoomImageFromThumb(thumb1View, R.drawable.image1);22 }23 });24 25 //取回系統預設的短時間長度動畫期間26 mShortAnimationDuration = getResources().getInteger(27 android.R.integer.config_shortAnimTime);28 }29 ...30 }
3.實現zoom動畫
你需要把從正常大小的view到擴大以後的view這個過程作成動畫。
1.指定想要zoom的圖片給ImageView。(理想情況下,這個bitmap的大小不應該比螢幕大)
2.計算這個ImageView的開始和結束位置
3.把四個點和縮放大小的屬性同時作成動畫,從開始的狀態到結束的狀態。這四個動畫被添加到AnimatorSet中,方便他們同時執行。
4.當使用者再次點擊螢幕時,動畫要執行回去。一樣道理,給ImageView一個View.OnClickListener,然後隱藏ImageView。
1 private void zoomImageFromThumb(final View thumbView, int imageResId) { 2 // 如果有動畫在執行,立即取消,然後執行現在這個動畫 3 if (mCurrentAnimator != null) { 4 mCurrentAnimator.cancel(); 5 } 6 7 // 載入高解析度的圖片 8 final ImageView expandedImageView = (ImageView) findViewById( 9 R.id.expanded_image); 10 expandedImageView.setImageResource(imageResId); 11 12 // 計算開始和結束位置的圖片範圍 13 final Rect startBounds = new Rect(); 14 final Rect finalBounds = new Rect(); 15 final Point globalOffset = new Point(); 16 17 // 開始的範圍就是ImageButton的範圍, 18 // 結束的範圍是容器(FrameLayout)的範圍 19 // getGlobalVisibleRect(Rect)得到的是view相對於整個硬體螢幕的Rect 20 // 即絕對座標,減去位移,獲得動畫需要的座標,即相對座標 21 // getGlobalVisibleRect(Rect,Point)中,Point獲得的是view在它在 22 // 父控制項上的座標與在螢幕上座標的位移 23 thumbView.getGlobalVisibleRect(startBounds); 24 findViewById(R.id.container) 25 .getGlobalVisibleRect(finalBounds, globalOffset); 26 startBounds.offset(-globalOffset.x, -globalOffset.y); 27 finalBounds.offset(-globalOffset.x, -globalOffset.y); 28 29 // Adjust the start bounds to be the same aspect ratio as the final 30 // bounds using the "center crop" technique. This prevents undesirable 31 // stretching during the animation. Also calculate the start scaling 32 // factor (the end scaling factor is always 1.0). 33 34 // 下面這段邏輯其實就是保持縱橫比 35 float startScale; 36 // 如果結束圖片的寬高比比開始圖片的寬高比大 37 // 就是結束時“視覺上”拉寬了(壓扁了)圖片 38 if ((float) finalBounds.width() / finalBounds.height() 39 > (float) startBounds.width() / startBounds.height()) { 40 // Extend start bounds horizontally 41 startScale = (float) startBounds.height() / finalBounds.height(); 42 float startWidth = startScale * finalBounds.width(); 43 float deltaWidth = (startWidth - startBounds.width()) / 2; 44 startBounds.left -= deltaWidth; 45 startBounds.right += deltaWidth; 46 } else { 47 // Extend start bounds vertically 48 startScale = (float) startBounds.width() / finalBounds.width(); 49 float startHeight = startScale * finalBounds.height(); 50 float deltaHeight = (startHeight - startBounds.height()) / 2; 51 startBounds.top -= deltaHeight; 52 startBounds.bottom += deltaHeight; 53 } 54 55 // Hide the thumbnail and show the zoomed-in view. When the animation 56 // begins, it will position the zoomed-in view in the place of the 57 // thumbnail. 58 59 // 隱藏小的圖片,展示大的圖片。當動畫開始的時候, 60 // 要把大的圖片發在小的圖片的位置上 61 62 //小的設定透明 63 thumbView.setAlpha(0f); 64 //大的可見 65 expandedImageView.setVisibility(View.VISIBLE); 66 67 // Set the pivot point for SCALE_X and SCALE_Y transformations 68 // to the top-left corner of the zoomed-in view (the default 69 // is the center of the view). 70 expandedImageView.setPivotX(0f); 71 expandedImageView.setPivotY(0f); 72 73 // Construct and run the parallel animation of the four translation and 74 // scale properties (X, Y, SCALE_X, and SCALE_Y). 75 AnimatorSet set = new AnimatorSet(); 76 set 77 .play(ObjectAnimator.ofFloat(expandedImageView, View.X, 78 startBounds.left, finalBounds.left)) 79 .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, 80 startBounds.top, finalBounds.top)) 81 .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, 82 startScale, 1f)).with(ObjectAnimator.ofFloat(expandedImageView, 83 View.SCALE_Y, startScale, 1f)); 84 set.setDuration(mShortAnimationDuration); 85 set.setInterpolator(new DecelerateInterpolator()); 86 set.addListener(new AnimatorListenerAdapter() { 87 @Override 88 public void onAnimationEnd(Animator animation) { 89 mCurrentAnimator = null; 90 } 91 92 @Override 93 public void onAnimationCancel(Animator animation) { 94 mCurrentAnimator = null; 95 } 96 }); 97 set.start(); 98 mCurrentAnimator = set; 99 100 // Upon clicking the zoomed-in image, it should zoom back down101 // to the original bounds and show the thumbnail instead of102 // the expanded image.103 104 // 再次點擊返回小的圖片,就是上面擴大的反向動畫。即預覽完成105 final float startScaleFinal = startScale;106 expandedImageView.setOnClickListener(new View.OnClickListener() {107 @Override108 public void onClick(View view) {109 if (mCurrentAnimator != null) {110 mCurrentAnimator.cancel();111 }112 113 // Animate the four positioning/sizing properties in parallel,114 // back to their original values.115 AnimatorSet set = new AnimatorSet();116 set.play(ObjectAnimator117 .ofFloat(expandedImageView, View.X, startBounds.left))118 .with(ObjectAnimator119 .ofFloat(expandedImageView,120 View.Y,startBounds.top))121 .with(ObjectAnimator122 .ofFloat(expandedImageView,123 View.SCALE_X, startScaleFinal))124 .with(ObjectAnimator125 .ofFloat(expandedImageView,126 View.SCALE_Y, startScaleFinal));127 set.setDuration(mShortAnimationDuration);128 set.setInterpolator(new DecelerateInterpolator());129 set.addListener(new AnimatorListenerAdapter() {130 @Override131 public void onAnimationEnd(Animator animation) {132 thumbView.setAlpha(1f);133 expandedImageView.setVisibility(View.GONE);134 mCurrentAnimator = null;135 }136 137 @Override138 public void onAnimationCancel(Animator animation) {139 thumbView.setAlpha(1f);140 expandedImageView.setVisibility(View.GONE);141 mCurrentAnimator = null;142 }143 });144 set.start();145 mCurrentAnimator = set;146 }147 });148 }