时间:2021-08-14 08:32:56 | 栏目:Android代码 | 点击:次
参考: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上扩大显示出来。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <ImageButton android:id="@+id/thumb_button_1" android:layout_width="100dp" android:layout_height="75dp" android:layout_marginRight="1dp" android:src="@drawable/thumb1" android:scaleType="centerCrop" android:contentDescription="@string/description_image_1" /> </LinearLayout> <!-- 这个不可见的ImageView持有上面的ImageButton zoom后的图片版本。 动画没有发生之前,它占据了整个屏幕。动画开始,这个View从上面 ImageButton的范围变化到他自己最终的范围。 --> <ImageView android:id="@+id/expanded_image" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" android:contentDescription="@string/description_zoom_touch_close" /> </FrameLayout>
2.设置zoom动画
在ImageButton上设置点击事件,执行zoom动画
public class ZoomActivity extends FragmentActivity { // 保存下当前动画类,以便可以随时结束动画 private Animator mCurrentAnimator; //系统的短时长动画持续时间(单位ms) // 对于不易察觉的动画或者频繁发生的动画 // 这个动画持续时间是最理想的 private int mShortAnimationDuration; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_zoom); // 给ImageButton设置点击事件 final View thumb1View = findViewById(R.id.thumb_button_1); thumb1View.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //执行zoom动画方法 zoomImageFromThumb(thumb1View, R.drawable.image1); } }); //取回系统默认的短时长动画持续时间 mShortAnimationDuration = getResources().getInteger( android.R.integer.config_shortAnimTime); } ... }
3.实现zoom动画
你需要把从正常大小的view到扩大以后的view这个过程作成动画。
1.指定想要zoom的图片给ImageView。(理想情况下,这个bitmap的大小不应该比屏幕大)
2.计算这个ImageView的开始和结束位置
3.把四个点和缩放大小的属性同时作成动画,从开始的状态到结束的状态。这四个动画被添加到AnimatorSet中,方便他们同时执行。
4.当用户再次点击屏幕时,动画要执行回去。一样道理,给ImageView一个View.OnClickListener,然后隐藏ImageView。
private void zoomImageFromThumb(final View thumbView, int imageResId) { // 如果有动画在执行,立即取消,然后执行现在这个动画 if (mCurrentAnimator != null) { mCurrentAnimator.cancel(); } // 加载高分辨率的图片 final ImageView expandedImageView = (ImageView) findViewById( R.id.expanded_image); expandedImageView.setImageResource(imageResId); // 计算开始和结束位置的图片范围 final Rect startBounds = new Rect(); final Rect finalBounds = new Rect(); final Point globalOffset = new Point(); // 开始的范围就是ImageButton的范围, // 结束的范围是容器(FrameLayout)的范围 // getGlobalVisibleRect(Rect)得到的是view相对于整个硬件屏幕的Rect // 即绝对坐标,减去偏移,获得动画需要的坐标,即相对坐标 // getGlobalVisibleRect(Rect,Point)中,Point获得的是view在它在 // 父控件上的坐标与在屏幕上坐标的偏移 thumbView.getGlobalVisibleRect(startBounds); findViewById(R.id.container) .getGlobalVisibleRect(finalBounds, globalOffset); startBounds.offset(-globalOffset.x, -globalOffset.y); finalBounds.offset(-globalOffset.x, -globalOffset.y); // Adjust the start bounds to be the same aspect ratio as the final // bounds using the "center crop" technique. This prevents undesirable // stretching during the animation. Also calculate the start scaling // factor (the end scaling factor is always 1.0). // 下面这段逻辑其实就是保持纵横比 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; } // Hide the thumbnail and show the zoomed-in view. When the animation // begins, it will position the zoomed-in view in the place of the // thumbnail. // 隐藏小的图片,展示大的图片。当动画开始的时候, // 要把大的图片发在小的图片的位置上 //小的设置透明 thumbView.setAlpha(0f); //大的可见 expandedImageView.setVisibility(View.VISIBLE); // Set the pivot point for SCALE_X and SCALE_Y transformations // to the top-left corner of the zoomed-in view (the default // is the center of the view). expandedImageView.setPivotX(0f); expandedImageView.setPivotY(0f); // Construct and run the parallel animation of the four translation and // scale properties (X, Y, SCALE_X, and SCALE_Y). AnimatorSet set = new AnimatorSet(); set .play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left, finalBounds.left)) .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top, finalBounds.top)) .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f)).with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f)); set.setDuration(mShortAnimationDuration); 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; // Upon clicking the zoomed-in image, it should zoom back down // to the original bounds and show the thumbnail instead of // the expanded image. // 再次点击返回小的图片,就是上面扩大的反向动画。即预览完成 final float startScaleFinal = startScale; expandedImageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mCurrentAnimator != null) { mCurrentAnimator.cancel(); } // Animate the four positioning/sizing properties in parallel, // back to their original values. AnimatorSet set = new AnimatorSet(); set.play(ObjectAnimator .ofFloat(expandedImageView, View.X, startBounds.left)) .with(ObjectAnimator .ofFloat(expandedImageView, View.Y,startBounds.top)) .with(ObjectAnimator .ofFloat(expandedImageView, View.SCALE_X, startScaleFinal)) .with(ObjectAnimator .ofFloat(expandedImageView, View.SCALE_Y, startScaleFinal)); set.setDuration(mShortAnimationDuration); set.setInterpolator(new DecelerateInterpolator()); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { thumbView.setAlpha(1f); expandedImageView.setVisibility(View.GONE); mCurrentAnimator = null; } @Override public void onAnimationCancel(Animator animation) { thumbView.setAlpha(1f); expandedImageView.setVisibility(View.GONE); mCurrentAnimator = null; } }); set.start(); mCurrentAnimator = set; } }); }