源码

1 activity_zoom.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:padding="16dp" ><TextViewstyle="?android:textAppearanceSmall"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/message_zoom_touch_expand" /><!--This is an example layout containing thumbnail image buttons that, when pressed,zoom in to show more detail. All of the zooming and animation logic is inthe ZoomActivity class.--><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:orientation="horizontal" ><!--These buttons don't have any decorations (3D bevel, etc.), but it's stillimportant to show feedback on touch or focus. The custom"ToughHighlightImageButton" ImageButton subclass helps achieve this by drawingthe standard system "pressed" and "focused" overlay upon user interaction.--><com.example.zoomanimation.TouchHighlightImageButtonandroid:id="@+id/thumb_button_1"android:layout_width="100dp"android:layout_height="75dp"android:layout_marginRight="1dp"android:contentDescription="@string/description_image_1"android:scaleType="centerCrop"android:src="@drawable/thumb1" /><com.example.zoomanimation.TouchHighlightImageButtonandroid:id="@+id/thumb_button_2"android:layout_width="100dp"android:layout_height="75dp"android:contentDescription="@string/description_image_2"android:scaleType="centerCrop"android:src="@drawable/thumb2" /></LinearLayout></LinearLayout><!--This initially-hidden ImageView will hold the expanded/zoomed version of theimages above. Without transformations applied, it takes up the entire screen.To achieve the "zoom" animation, this view's bounds are animated from thebounds of the thumbnail buttons above, to its final laid-out bounds. The implementationof this animation is in the ZoomActivity class.--><ImageViewandroid:id="@+id/expanded_image"android:layout_width="match_parent"android:layout_height="match_parent"android:contentDescription="@string/description_zoom_touch_close"android:visibility="invisible" /></FrameLayout>

2 strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources><string name="app_name">ZoomAnimation</string><string name="hello_world">Hello world!</string><string name="action_settings">Settings</string><string name="message_zoom_touch_expand">Touch a photo to expand it.</string><string name="description_image_1">Image 1</string><string name="description_image_2">Image 2</string><string name="description_zoom_touch_close">Expanded image (touch to close)</string></resources>

3 TouchHighlightImageButton.java

package com.example.zoomanimation;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageButton;public class TouchHighlightImageButton extends ImageButton {private Drawable mForegroundDrawable;private Rect mCachedBounds = new Rect();public TouchHighlightImageButton(Context context) {super(context);init();}public TouchHighlightImageButton(Context context, AttributeSet attrs) {super(context, attrs);init();}public TouchHighlightImageButton(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init();}private void init() {// Reset default ImageButton background and padding.setBackgroundColor(0);setPadding(0, 0, 0, 0);// Retrieve the drawable resource assigned to the// android.R.attr.selectableItemBackground// theme attribute from the current theme.TypedArray a = getContext().obtainStyledAttributes(new int[] { android.R.attr.selectableItemBackground });mForegroundDrawable = a.getDrawable(0);mForegroundDrawable.setCallback(this);a.recycle();}@Overrideprotected void drawableStateChanged() {super.drawableStateChanged();// Update the state of the highlight drawable to match// the state of the button.if (mForegroundDrawable.isStateful()) {mForegroundDrawable.setState(getDrawableState());}// Trigger a redraw.invalidate();}@Overrideprotected void onDraw(Canvas canvas) {// First draw the image.super.onDraw(canvas);// Then draw the highlight on top of it. If the button is neither// focused// nor pressed, the drawable will be transparent, so just the image// will be drawn.mForegroundDrawable.setBounds(mCachedBounds);mForegroundDrawable.draw(canvas);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);// Cache the view bounds.mCachedBounds.set(0, 0, w, h);}
}

4 ZoomActivity.java

package com.example.zoomanimation;import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;public class ZoomActivity extends Activity {/*** Hold a reference to the current animator, so that it can be canceled* mid-way.*/private Animator mCurrentAnimator;/*** The system "short" animation time duration, in milliseconds. This* duration is ideal for subtle animations or animations that occur very* frequently.*/private int mShortAnimationDuration;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_zoom);// Hook up clicks on the thumbnail views.final View thumb1View = findViewById(R.id.thumb_button_1);thumb1View.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {zoomImageFromThumb(thumb1View, R.drawable.image1);}});final View thumb2View = findViewById(R.id.thumb_button_2);thumb2View.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {zoomImageFromThumb(thumb2View, R.drawable.image2);}});// Retrieve and cache the system's default "short" animation time.mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);}/*** "Zooms" in a thumbnail view by assigning the high resolution image to a* hidden "zoomed-in" image view and animating its bounds to fit the entire* activity content area. More specifically:** <ol>* <li>Assign the high-res image to the hidden "zoomed-in" (expanded) image* view.</li>* <li>Calculate the starting and ending bounds for the expanded view.</li>* <li>Animate each of four positioning/sizing properties (X, Y, SCALE_X,* SCALE_Y) simultaneously, from the starting bounds to the ending bounds.</li>* <li>Zoom back out by running the reverse animation on click.</li>* </ol>** @param thumbView*            The thumbnail view to zoom in.* @param imageResId*            The high-resolution version of the image represented by the*            thumbnail.*/private void zoomImageFromThumb(final View thumbView, int imageResId) {// If there's an animation in progress, cancel it immediately and// proceed with this one.if (mCurrentAnimator != null) {mCurrentAnimator.cancel();}// Load the high-resolution "zoomed-in" image.final ImageView expandedImageView = (ImageView) findViewById(R.id.expanded_image);expandedImageView.setImageResource(imageResId);// Calculate the starting and ending bounds for the zoomed-in image.// This step// involves lots of math. Yay, math.final Rect startBounds = new Rect();final Rect finalBounds = new Rect();final Point globalOffset = new Point();// The start bounds are the global visible rectangle of the thumbnail,// and the// final bounds are the global visible rectangle of the container view.// Also// set the container view's offset as the origin for the bounds, since// that's// the origin for the positioning animation properties (X, Y).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 horizontallystartScale = (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 verticallystartScale = (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() {@Overridepublic void onAnimationEnd(Animator animation) {mCurrentAnimator = null;}@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onAnimationEnd(Animator animation) {thumbView.setAlpha(1f);expandedImageView.setVisibility(View.GONE);mCurrentAnimator = null;}@Overridepublic void onAnimationCancel(Animator animation) {thumbView.setAlpha(1f);expandedImageView.setVisibility(View.GONE);mCurrentAnimator = null;}});set.start();mCurrentAnimator = set;}});}}

分析

对zoomImageFromThumb方法添加Log,打印数据理解下:

private void zoomImageFromThumb(final View thumbView, int imageResId) {// If there's an animation in progress, cancel it immediately and// proceed with this one.if (mCurrentAnimator != null) {mCurrentAnimator.cancel();}// Load the high-resolution "zoomed-in" image.final ImageView expandedImageView = (ImageView) findViewById(R.id.expanded_image);expandedImageView.setImageResource(imageResId);// Calculate the starting and ending bounds for the zoomed-in image.// This step// involves lots of math. Yay, math.final Rect startBounds = new Rect();final Rect finalBounds = new Rect();final Point globalOffset = new Point();// The start bounds are the global visible rectangle of the thumbnail,// and the// final bounds are the global visible rectangle of the container view.// Also// set the container view's offset as the origin for the bounds, since// that's// the origin for the positioning animation properties (X, Y).thumbView.getGlobalVisibleRect(startBounds);findViewById(R.id.container).getGlobalVisibleRect(finalBounds, globalOffset);Log.d("ZoomActivity", "before startBounds =" + startBounds);Log.d("ZoomActivity", "before finalBounds =" + finalBounds);int[] thumbViewLocation = new int[2];thumbView.getLocationOnScreen(thumbViewLocation);int thumbViewX = thumbViewLocation[0];int thumbViewY = thumbViewLocation[1];int[] containerLocation = new int[2];findViewById(R.id.container).getLocationOnScreen(containerLocation);int containerX = containerLocation[0];int containerY = containerLocation[1];Log.d("ZoomActivity", "getLocationOnScreen thumbViewX =" + thumbViewX + "   thumbViewY=" + thumbViewY);Log.d("ZoomActivity", "getLocationOnScreen containerX =" + containerX + "   containerY=" + containerY);startBounds.offset(-globalOffset.x, -globalOffset.y);finalBounds.offset(-globalOffset.x, -globalOffset.y);Log.d("ZoomActivity", "after startBounds =" + startBounds);Log.d("ZoomActivity", "after finalBounds =" + finalBounds);// 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 horizontallystartScale = (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 verticallystartScale = (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() {@Overridepublic void onAnimationEnd(Animator animation) {mCurrentAnimator = null;}@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onAnimationEnd(Animator animation) {thumbView.setAlpha(1f);expandedImageView.setVisibility(View.GONE);mCurrentAnimator = null;}@Overridepublic void onAnimationCancel(Animator animation) {thumbView.setAlpha(1f);expandedImageView.setVisibility(View.GONE);mCurrentAnimator = null;}});set.start();mCurrentAnimator = set;}});}

Log:

01-05 00:05:33.585 16826 16826 D ZoomActivity: before startBounds =Rect(32, 246 - 232, 396)
01-05 00:05:33.585 16826 16826 D ZoomActivity: before finalBounds =Rect(0, 144 - 720, 1184)
01-05 00:05:33.586 16826 16826 D ZoomActivity: getLocationOnScreen thumbViewX =32   thumbViewY=246
01-05 00:05:33.586 16826 16826 D ZoomActivity: getLocationOnScreen containerX =0   containerY=144
01-05 00:05:33.586 16826 16826 D ZoomActivity: after startBounds =Rect(32, 102 - 232, 252)
01-05 00:05:33.586 16826 16826 D ZoomActivity: after finalBounds =Rect(0, 0 - 720, 1040)

A,

从Log知:getGlobalVisibleRect方法返回的Rect对象的左上角坐标与getLocationOnScreen方法是一致的,也就理解了:

getGlobalVisibleRect获取全局坐标系的一个视图区域, 返回一个填充的Rect对象,该Rect是基于总整个屏幕的。

对view进行offset处理是为了去除相对屏幕的偏移量,使”子View“的Rect的左上角坐标是相对"父View",这样利于计算”子View“相对”父View“的最终显示位置

B,

  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;
        }
   为了使用相同的宽高比例,避免出现较大的不正常拉伸 ,需要进行计算:

   1.满足if判断说明:“屏幕宽高比例” 大于 “缩略图宽高比例”,说明最终显示的“宽度”较大,为了较少变形拉伸,因此需要在“宽度”上进行调整,此时就应该拿相对比较接近的"原始高度"因素进行计算(为了较少偏差),首先通过"高度"计算出“缩放因子”(startScale),使用同样的缩放因子(startScale)计算出“应该有的原始宽度”,然后用“应该有的原始宽度”减去“真实的原始宽度“就是总的宽度偏差,然后除以2算出单侧的偏差(deltaHeight),然后对”真实的原始宽度“,用”单侧的偏差(deltaHeight)“进行微调 

   2.满足else判断说明:“屏幕宽高比例” 小于 “缩略图宽高比例”,说明最终显示的“高度”较大,为了较少变形拉伸,因此需要在“高度”上进行调整,类似上面分析...

上面使用了:”相同的宽高比例“及"中心剪切技术"等概念。

Android 对一个View进行缩放处理(放大或缩小View)案例相关推荐

  1. android手势放大自动还原,ImageView通过matrix实现手势缩放,放大,缩小 ,移动

    转载自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/1023/1579.html 测试有效 关于ImageView的手势缩放, ...

  2. Android 安卓动画 属性动画 - 缩放动画

    引入 属性动画的出现,弥补了补间动画的不足之处,补间动画,只是改变了表面上的东西,但是其中属性并未改变,而属性动画相反,改变了表面上的东西,并且也更改了其属性. 类:ObjectAnimator 用于 ...

  3. 如何放大和缩小Word文档

    If you need to see a part of your Word document up close, or if you need to see more of the page tha ...

  4. android 自定义view,缩放放大,平移边界检测

    由于项目的需要,自定义个view,控制父控件,既可以缩放放大,滑动边界检测.自己实现了通过父控件就能操作子控件的自定义view,直接引用就可以使用. 下面是我实现的一个思路,贴了部分代码,大家可以参考 ...

  5. Android开发之View双指缩放ViewGroup双指缩放视频双指缩放图片双指缩放

    老套路先上图 核心代码使用view的缩放API即可 setScaleX(scale); setScaleY(scale); 在看下自定义可缩放的view package cn.xiayiye5.xia ...

  6. android图片缩放模式,Android使用缩放动画放大你的图片

    注:本篇文章是对官方开发文档的翻译,加上自己的理解和分析. 地址:https://developer.android.com/training/animation/zoom 本篇文章所实现的功能: 触 ...

  7. Android 展示一个图片,可以双击放大/缩小(放大后可以移动)

    布局***.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:a ...

  8. android 方大动画,动画 -- View动画 -- 缩放动画

    一.概念 缩放动画,子类:ScaleAnimation,标签: 它可以使View具有放大或者缩小的动画效果. 二.实现 1. XML实现 标签常用属性如下: android:fromXScale:起始 ...

  9. 【Animations】使用缩放动画放大视图(7)

    原文 概要 本课程演示如何执行触摸缩放动画,这对诸如照片库等应用程序可以将视图从缩略图动画化为充满屏幕的全尺寸图像. 以下是触摸缩放动画看起来像展开图像缩略图以填充屏幕: 视频地址:https://d ...

最新文章

  1. 图像处理理论(二)——形态学、边缘检测、图像金字塔
  2. 从大学生到职场人,一段深刻的思维认知升级补丁
  3. 为对象分配内存TLAB
  4. python皮卡丘编程代码_再接再厉,用python编程13行代码解方程组(纯字符)
  5. 控制for each循环次数_CCF CSP编程题解201312-1:出现次数最多的数
  6. 大型互联网系统的监控流水线
  7. Linux实战 | 搭建Linux(CentOS6.8版)_1
  8. 303.区域和检索-数组不可变
  9. 你的奋斗也许只是一个屁
  10. html——form表单提交方法submit和button
  11. Python socket文件上传下载
  12. 折页损失函数代码实现
  13. php导出word文件(二)
  14. 考研数学汤家凤笔记第一章:极限与连续
  15. 西南大学实验室考试自测题学习
  16. 疯狂python讲义学习日志11——并发编程
  17. python创建学生类姓名学号_Python练习题:由用户输入学生学号与姓名,数据用字典存储,最终输出学生信息(按学号由小到大显示)。...
  18. ECS开发(一、)ECS是什么?
  19. 用Java写贪吃蛇小游戏
  20. 如何加载带有 AM、PM 的时间类型数据

热门文章

  1. HTTP就绪状态和HTTP状态码
  2. 【学习笔记】迁移学习分类
  3. python爬取音乐源码_手把手教你使用Python抓取QQ音乐数据(第一弹)
  4. java设计模式-观察者模式和中介者模式的异同
  5. python输入生日判断星座_用python条件语句判断星座
  6. H5页面播放M4a音频文件
  7. 处世36计之第17计--恐吓计
  8. 洛谷题目P1425 小鱼的游泳时间
  9. 在阅读中培养自己的注意力
  10. Hadoop3.x集群搭建及配置的完整操作流程