在Android5.0版本之前,我们的Activity进入退出动画都比较生硬,通常都是调用overridePendingTransition(int enterAnim, int exitAnim)来展示Activty的进出动画,当然了也可以设置overridePendingTransition(0, 0)来取消Activty的切换动画。到了5.1这个版本之后,Activity的进出动画就已经很生动了。根本原因是Transition这个类的出现,它为我们提供了两种Activity transition :内容transition与共享元素的transition。

现在我们需要了解的API:

1 .FEATURE_ACTIVITY_TRANSITIONS(added in API level 21)

ActivityOptions 调用makeSceneTransitionAnimation(android.app.Activity, android.util.Pair[]) 方法时,允许活动的窗口接收或发送Transition。[○・`Д´・ ○]

代码实现:

 @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);        setContentView(R.layout.activity_sample);        }

xml实现需要写在style中(默认就是true)

<item name="android:windowActivityTransitions">trueitem>

2 .FEATURE_CONTENT_TRANSITIONS(added in API level 21)

使用TransitionManager来管理过渡动画时,设置窗口内容更改的标志。

 @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);        setContentView(R.layout.activity_sample);        }

xml实现需要写在style中(默认就是true)

<item name="android:windowContentTransitions">trueitem>

3 . setAllowEnterTransitionOverlap
当设置了setEnterTransition(android.transition.Transition)之后,Transition动画一般会比跳转Activity的速度慢一些,所以会有执行了一半Transition动画之后,然后就跳转到了另一个Activity。设置true,Transition开始的时候调用Activity,设置false,那就等待Transition完成,然后再调用Activity,默认是true。

代码中:

 getWindow().setAllowEnterTransitionOverlap(true);

xml写在stytle中:

<item name="android:windowAllowEnterTransitionOverlap">trueitem>

4 . setSharedElementsUseOverlay
设置转场动画期间使用Overlay。true表示共享元素应该用Overlay转换,false表示在正常的View层次结构中转换。默认值是true。(个人建议尽量不要设置false)
代码中:

  getWindow().setSharedElementsUseOverlay(true);

xml写在stytle中:

<item name="android:windowSharedElementsUseOverlay">trueitem>

ViewOverlay是Android 4.3新增的一个类,它位于view最上面,是一个透明层,因为它是View绘制之后才绘制的,所以我们可以在这个层之上添加内容而不会影响到整个布局结构。

5 .postponeEnterTransition(added in API level 21)
在设置了makeSceneTransitionAnimation(Activity, android.util.Pair[])之后,推迟转场动画。这个方法会延迟启动进入Activity直到加载完所有的数据。在此之前,活动不会进入新的窗口,让窗口保持透明。所以必须调startPostponedEnterTransition()以允许Activity开始转换。如果Activity没有使用 makeSceneTransitionAnimation(Activity, android.util.Pair[]),那么设置这个方法设置了也无效。

6 . startPostponedEnterTransition (added in API level 21)
postponeEnterTransition()被调用后开始推迟的转换。如果调用postponeEnterTransition(),则必须调用startPostponedEnterTransition()以使您的活动开始绘制。


简单的看了几个API,后面我们会用到的。那我们来看两个简单的例子:

...省略无数代码ActivityOptionsCompat options = ActivityOptionsCompat.makeScaleUpAnimation(ivImage, view.getWidth(),view.getHeight(), 0, 0);mContext.startActivity(intent, options.toBundle());...省略无数代码

上面我贴上了关键的代码ヾ(=・ω・=)o

ActivityOptionsCompat makeScaleUpAnimation (View source,                 int startX,                 int startY,                 int startWidth,                 int startHeight)source:目标ViewstartX:根据目标View从X坐标开始动画startY:根据目标View从Y坐标开始动画startWidth:新的Activity从什么宽度开始动画startHeight:新的Activity从什么高度开始动画

这个方法是根据目标View,给一个放大的效果然后进行转场动画的。


先看效果图:

首先呢,我们用到了共享元素,然后进行转场动画。所以先在XML中定义Transition

  • 建立transition文件夹,然后创建change_image_transform.xml
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">    <changeBounds        android:duration="500"        android:interpolator="@android:interpolator/linear_out_slow_in"/>    <changeImageTransform        android:duration="500"        android:interpolator="@android:interpolator/linear_out_slow_in"/>transitionSet>
  • 跳转页面的时候我们看到页面是从上与从顶部分别进入的。这是因为定义TransitionSlide,所以我们分别创建进入与 退出的Transitionsimple_activity_enter_transition.xmlsimple_activity_exit_transition.xml两个写法正好相反,所以只贴出进入的方式。
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">    <slide        android:duration="500"        android:slideEdge="top">        <targets>            <target android:targetId="@id/relative_top"/>        targets>    slide>    <slide android:duration="500" android:slideEdge="bottom" >        <targets>            <target android:targetId="@id/relative_bottom"/>        targets>    slide>transitionSet>

标签里面可以指定目标ID,可以选择ID指定动画,也可以除去目标ID,这个ID不执行动画

  • Transition最后需要在style中适配,然后应用在Activity的主题中。
<style name="SecondActivityTheme" parent="AppTheme">   <item name="android:windowEnterTransition">@transition/simple_activity_enter_transition   "android:windowExitTransition">@transition/simple_activity_exit_transition   "android:windowSharedElementEnterTransition">@transition/change_image_transform  style>
  • 看一下跳转的Activity布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent">    <android.support.design.widget.AppBarLayout        android:id="@+id/appbar"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:theme="@style/AppTheme.AppBarOverlay">        <android.support.v7.widget.Toolbar            android:id="@+id/toolbar"            android:layout_width="match_parent"            android:layout_height="?attr/actionBarSize"            android:background="?attr/colorPrimary"            app:contentInsetEnd="16dp" />    android.support.design.widget.AppBarLayout>    <RelativeLayout        android:id="@+id/relative_top"        android:layout_width="match_parent"        android:layout_height="200dp"        android:layout_below="@id/appbar"        android:transitionGroup="true">        <ImageView            android:id="@+id/full_image"            android:layout_width="match_parent"            android:layout_height="match_parent" />        <ImageView            android:id="@+id/full_pic"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:transitionName="profileImage" />        <TextView            android:id="@+id/content_tv"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignBottom="@id/full_pic"            android:layout_centerInParent="true"            android:layout_marginTop="10dp"            android:textColor="@android:color/holo_orange_dark"            android:textSize="20sp"            android:transitionName="profileText" />    RelativeLayout>    <RelativeLayout        android:id="@+id/relative_bottom"        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:layout_below="@id/relative_top"        android:background="@android:color/darker_gray"        android:transitionGroup="true">        <TextView            android:id="@+id/tv_des"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:padding="10dp"            android:textColor="@android:color/holo_orange_light"            android:textSize="21sp" />    RelativeLayout>RelativeLayout>
...省略布局    <ImageView        android:id="@+id/list_picture"        android:layout_width="@dimen/picture_width"        android:layout_height="@dimen/picture_height"        android:transitionName="profileImage" />    <TextView        android:id="@+id/tv_author"        android:transitionName="profileText"        android:textSize="21sp" />...省略布局

重点关注android:transitionName="..."android:transitionGroup="true"这两个属性值。
其中第一个:在布局文件中对于要共享View添加的Flag。需要共享View的ID可以不同,但是设定的这个name需要一致。
第二个:应该将这个ViewGroup视为单个实体,也就是当成一个Transition来处理。

  • 代码里面比较简单,点击Item的时候,跳转到另一个界面。
    Intent intent = new Intent(mContext, SecondActivity.class);        intent.putExtra(SecondActivity.EXTRA_AUTHOR, item.getAuthor());        intent.putExtra(SecondActivity.EXTRA_CONTACT, item.getQuote());        Pair imagePair = Pair.create((View)ivImage, "profileImage");        Pair textPair = Pair.create((View)tvAuthor, "profileText");        ActivityOptionsCompat options = ActivityOptionsCompat.                  makeSceneTransitionAnimation((Activity) mContext, imagePair, textPair);        mContext.startActivity(intent, options.toBundle());

ActivityOptionsCompat makeSceneTransitionAnimation (Activity activity, Pair…

...省略代码 Picasso.with(this)                .load(R.drawable.k)                .into(imageView, new Callback() {                    @Override                    public void onSuccess() {                        scheduleStartPostponedTransition(imageView);                    }                    @Override                    public void onError() {                    }                });        postponeEnterTransition();        fullImage.setAlpha(0f);        //添加共享元素监听        getWindow().getSharedElementEnterTransition().addListener(new Transition.TransitionListener() {            //完成元素共享动画之后,显示一张模糊图片            @Override            public void onTransitionEnd(Transition transition) {                Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.l);                showBlur(bitmap,fullImage);            }        });    }   private void showBlur(Bitmap bg, View view) {        //Radius out of range (0 < r <= 25).        float radius = 10;        Bitmap overlay = Bitmap.createBitmap((int)(view.getMeasuredWidth()), (int)(view.getMeasuredHeight()), Bitmap.Config.RGB_565);        Canvas canvas = new Canvas(overlay);        canvas.translate(-view.getLeft(), -view.getTop());        canvas.drawBitmap(bg, 0, 0, null);        //初始化RenderScript        RenderScript rs = RenderScript.create(SecondActivity.this);        //创建一个Allocation,为数据提供存储功能,Allocation允许将数组从Java代码传递到RenderScript代码        Allocation overlayAlloc = Allocation.createFromBitmap(rs, overlay);        //使用kernels中的RenderScript,在其子类中 ScriptIntrinsic.实现了部分效果(高斯模糊)        ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rs, overlayAlloc.getElement());        blur.setInput(overlayAlloc);        blur.setRadius(radius);        blur.forEach(overlayAlloc);        overlayAlloc.copyTo(overlay);        view.setBackground(new BitmapDrawable(getResources(), overlay));        view.animate().setDuration(1000).alpha(1f);        rs.destroy();    }    private void scheduleStartPostponedTransition(final View sharedElement) {        sharedElement.getViewTreeObserver().addOnPreDrawListener(                new ViewTreeObserver.OnPreDrawListener() {                    @Override                    public boolean onPreDraw() {                        sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);                        startPostponedEnterTransition();                        return true;                    }                });    }    @Override    public void onBackPressed() {//        super.onBackPressed();        finishAfterTransition();    } ...省略代码

关键的代码就是这些,我顺便加了一个高斯模糊的效果(RenderScript ),然后退出的界面的时候调用finishAfterTransition()。在Picasso中写了一个监听,为的是如果加载的是网络图片,数据加载需要一定的时间,配合startPostponedEnterTransition()完全加载出图片之后再显示共享动画效果。

OK,结合着上篇的内容,共享动画效果我们就懂了一些了。
这种玩意如果想向下兼容到4.4之前,很不容易,尤其是在加上statusBar这种东西,向后兼容那就更费劲了。不过写代码的时候还是一定要加上if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)

天气转暖了,终于不用穿羽绒衣上班了。真爽(◕ᴗ◕✿)(◕ᴗ◕✿)

更多相关文章

  1. Android(安卓)JNI之OpenSSL
  2. Android(安卓)N代码分析:requestLayout
  3. Android的Toolbar(含溢出菜单设置[弹出菜单的使用])的使用PopMen
  4. android蓝牙耳机录音程序主要代码
  5. SystemProperties與Settings.System
  6. 2018最新 Android(安卓)面试题总结(二)
  7. 如何开始分析一份开源软件代码
  8. Notification的功能与用法
  9. ndk初体验

随机推荐

  1. 【整理】Android中的USB中的UsbAccessory
  2. 自定义Toast
  3. Android(安卓)游戏引擎分类汇总
  4. android中数据存储及对xml的解析
  5. Android(安卓)屏幕分辩率相关问题
  6. Android开发资源 汇总
  7. Android完美解决输入框EditText隐藏密码
  8. Android(安卓)实用工具Hierarchy Viewer
  9. Android(安卓)属性动画(一):Animator属性动
  10. Google Maps 工程的小问题