这个是developer.android.com的demo,初学android,做下笔记.

目的: 实现点击缩略图,动画放大为大图,点击大图,反向动画为缩略图.

思路: 最外层用FrameLayout,便于将加载大图的ImageView覆盖在缩略图之上,先将此imageView隐藏,动画时再显示.

layout

<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">        <TextView style="?android:textAppearanceSmall"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@string/message_zoom_touch_expand" />        <LinearLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginTop="16dp"            android:orientation="horizontal">            <!-- TouchHighlightImageButton是一个自定义ImageButton,点击时盖上一层半透明图层,以标识focused 和 pressed 状态-->            <com.example.android.animationsdemo.TouchHighlightImageButton                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" />            <com.example.android.animationsdemo.TouchHighlightImageButton                android:id="@+id/thumb_button_2"                android:layout_width="100dp"                android:layout_height="75dp"                android:src="@drawable/thumb2"                android:scaleType="centerCrop"                android:contentDescription="@string/description_image_2" />        </LinearLayout>    </LinearLayout>    <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>

ZoomActivity

package com.example.android.animationsdemo;import android.animation.Animator;import android.animation.AnimatorListenerAdapter;import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.content.Intent;import android.graphics.Point;import android.graphics.Rect;import android.os.Bundle;import android.support.v4.app.FragmentActivity;import android.support.v4.app.NavUtils;import android.util.Log;import android.view.MenuItem;import android.view.View;import android.view.animation.DecelerateInterpolator;import android.widget.ImageView;public class ZoomActivity extends FragmentActivity {    /**     * 存放属性动画对象,方便后面中途取消动画时用.     */    private Animator mCurrentAnimator;    /**     * 动画过场时间     */    private int mShortAnimationDuration;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_zoom);        //这里没什么好说的,thumb1View ,thumb2View 2个缩略图        final View thumb1View = findViewById(R.id.thumb_button_1);        thumb1View.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                zoomImageFromThumb(thumb1View, R.drawable.image1);            }        });        final View thumb2View = findViewById(R.id.thumb_button_2);        thumb2View.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                zoomImageFromThumb(thumb2View, R.drawable.image2);            }        });        mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);       // mShortAnimationDuration = 2000; 可以改长一点观察动画的详细过程    }     //无关,不解释    @Override    public boolean onOptionsItemSelected(MenuItem item) {        switch (item.getItemId()) {            case android.R.id.home:                NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));                return true;        }        return super.onOptionsItemSelected(item);    }        /*     * @param thumbView  要放大的缩略图View.     * @param imageResId 大图Id.     */    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);        //重点开始: 计算动画的开始和结束边界,其实就是计算2个矩形        final Rect startBounds = new Rect();        final Rect finalBounds = new Rect();        final Point globalOffset = new Point();        // 获得缩略图的矩形,注意:使用的是绝对坐标,相对于全屏        thumbView.getGlobalVisibleRect(startBounds);                //获得大图的(这里是放置大图的FrameLayout,一回事)的矩形,和偏移量        //所谓"偏移量",指绝对坐标和相对坐标之差,之于为什么要这么干,因为属性动画中用的全是相对坐标        findViewById(R.id.container).getGlobalVisibleRect(finalBounds, globalOffset);                //用偏移量修正2个矩形        startBounds.offset(-globalOffset.x, -globalOffset.y);        finalBounds.offset(-globalOffset.x, -globalOffset.y);                // 1.计算高和宽的Scale,        // 2.如果缩略图和大图的高宽比不一样,先在startBounds中修正它        //    因为动画过程中出现拉伸的状况就不美了,我没测试过        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);        expandedImageView.setVisibility(View.VISIBLE);        // 设置动画开始的SCALE_X 和SCALE_Y变化的左上角原点,如果不设置的话默认从View的center开始        expandedImageView.setPivotX(0f);        expandedImageView.setPivotY(0f);        // 到这就没啥好说的了        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))//最后的Scale肯定是1                .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;        //放大后再点击,缩回原状         final float startScaleFinal = startScale;        expandedImageView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                if (mCurrentAnimator != null) {                    mCurrentAnimator.cancel();                }                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;            }        });    }}

主要知识点:

1. 绝对坐标及相对坐标的获取和转换,getGlobalVisibleRect(Rect r, Point offset);

2. 属性动画使用的一些注意点,比如SCALE_X 和SCALE_Y变化原点的设置等.

附上一个效果图



更多相关文章

  1. android 通过主题设置activity统一切换动画
  2. android显示大图片的一些技巧
  3. Android入门笔记 - 界面开发 - Animation
  4. Android(安卓)animation - 基础
  5. Android(安卓)环形布局: FloatingActionButton + ConstraintLayou
  6. MTK Android(安卓)P 开机无动画,无铃声问题和开机铃声不同步,首次
  7. Android(安卓)activity简单跳转动画(overridePendingTransition)
  8. android之两种设置全屏或者无标题的方法
  9. android studio aar 添加依赖

随机推荐

  1. Android应用程序内部启动Activity过程(sta
  2. Android(安卓)文字过长TextView如何自动
  3. Android进阶——Android事件分发机制之di
  4. Android(安卓)Service生命周期及用法!
  5. Android(安卓)使用WiFi打印
  6. Android之个性化ListView实现
  7. Android系统架构基本模式解析
  8. 如何实现android EditText允许输入字母和
  9. Android(安卓)ROM分析(1):刷机原理及方法
  10. Android(安卓)日历开发教程[六]