美文网首页Android动画
低版本实现共享元素动画

低版本实现共享元素动画

作者: 小武站台 | 来源:发表于2016-08-30 16:20 被阅读878次

    译文的GitHub地址:低版本实现共享元素动画

    译者注:好久没录gif 了 凑合的看吧 哈哈 希望对你们有点帮助

    Share Element Transition

    共享元素过渡动画是material设计重要的一部分,activity切换动画是一个让用户记住我们app的好方法。在切换动画中,共享元素动画可能是最常用的,在淘宝,各种外卖app都能看到这种动画(ios)。

    共享元素动画在Lollipop+很容易实现,但是如果你想应用在老版本上,有点麻烦,但也没那么可怕,下面我会告诉你怎么实现它。

    主要步骤

    简单起见,我们的例子是从Activity A->Activity B并且他们共享一个元素(图片内容)。

    Activity A是一个RecycleView列表页面,点击会item会跳转到B页面

    Activity B是一个只显示图片的页面

    下面是几个重要的步骤。

    1. Activity A捕捉共享元素的初始值(位于屏幕的坐标,view的宽高),然后通过Intent传递给Activity B
    2. Activity B初始设成全透明
    3. Activity B读取传递过来的值并准备动画场景
    4. Activity B开始执行共享元素动画

    下面我会详解这些步骤并给出示范代码。

    首先,我们把Activity A的共享view称为origin view,Activity B的共享view叫destination view,记住:这两个view 虽然它们被称为共享,但它们实际上是两个独立的视图对象,只不过内容相同。

    让我们开始吧。

    1.Activity A 捕捉和传递初始值

    在RecycleView的点击事件相应中,我们获取图片ImageView的相关信息,并传递给B

    itemClickListener = new MainAdapter.RecycleItemClickListener() {
                @Override
                public void onItemClick(View view, int position) {
                    Intent intent = new Intent();
                    intent.setClass(A.this, B.class);
                    intent.putExtra(VIEW_INFO_EXTRA, createViewInfoBundle(view));
                    startActivity(intent);
                    overridePendingTransition(0, 0);
                }
            };
    

    要记住调用overridePendingTransition(0, 0)禁用默认的过渡动画。

    方法createViewInfoBundle主要返回view的位置和宽高

      private Bundle createViewInfoBundle(View view) {
        int[] screenLocation = new int[2];
        view.getLocationOnScreen(screenLocation);
        Bundle b = new Bundle();
        int left = screenLocation[0];
        int top = screenLocation[1];
        int width = view.getWidth();
        int height = view.getHeight();
        b.putInt("left", left);
        b.putInt("top", top);
        b.putInt("width", width);
        b.putInt("height", height);
        return b;
    }
    

    2.Activity B 背景设成透明

    B页面的布局很简单,ImageView默认隐藏

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout android:id="@+id/container_detail"
                  xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:gravity="center"
                  android:orientation="vertical">
    
        <ImageView
            android:id="@+id/iv_detail"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:scaleType="centerCrop"
            android:visibility="invisible"/>
    
    </LinearLayout>
    

    Activity B背景设成透明

    <style name="Transparent" parent="AppTheme">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>
    

    3.Activity B 接收信息并准备动画场景

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_article_image);
        ...
        destinationView = findViewById(R.id.iv_detail);
        containerView = (LinearLayout) findViewById(R.id.container_detail);
        // 取出传递过来的originView信息
        extractViewInfoFromBundle(getIntent());
        //简单起见,我们直接设置本地图片 不使用网络加载图片
        destinationView.setBackgroundDrawable(getResources().getDrawable(R.drawable.ic));
        onUiReady();
        ...
    }
    
    
      private void onUiReady() {
            destinationView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    // remove previous listener
                    destinationView.getViewTreeObserver().removeOnPreDrawListener(this);
                    //准备场景
                    prepareScene();
                    //播放动画
                    runEnterAnimation();
                    return true;
                }
            });
        }
    
     private void prepareScene() {
            int[] screenLocation = new int[2];
            destinationView.getLocationOnScreen(screenLocation);
            //移动到起始view位置   
            deltaX = originViewLeft - screenLocation[0];
            deltaY = originViewTop - screenLocation[1];
            destinationView.setTranslationX(deltaX);
            destinationView.setTranslationY(deltaY);
            //缩放到起始view大小
            scaleX = (float) originViewWidth / destinationView.getWidth();
            scaleY = (float) originViewHeight / destinationView.getHeight();
            destinationView.setScaleX(scaleX);
            destinationView.setScaleY(scaleY);
        }
    

    4.Activity B 执行动画

    private void runEnterAnimation() {
            destinationView.setVisibility(View.VISIBLE);
            //获取图片的颜色,设置背景色
            Bitmap bitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.ic)).getBitmap();
            Palette p = Palette.generate(bitmap);
            Palette.Swatch swatch = p.getDarkVibrantSwatch();
            containerView.setBackgroundColor(swatch.getRgb());
            //执行动画
            destinationView.animate()
                    .setDuration(DEFAULT_DURATION)
                    .setInterpolator(DEFAULT_INTERPOLATOR)
                    .scaleX(1f)
                    .scaleY(1f)
                    .translationX(0)
                    .translationY(0)
                    .start();
    
        }
    

    别忘了点击返回键的退出动画

        @Override
        public void onBackPressed() {
            runExitAnimation();
        }
    
    
    
        private void runExitAnimation() {
            destinationView.animate()
                    .setDuration(DEFAULT_DURATION)
                    .setInterpolator(DEFAULT_INTERPOLATOR)
                    .scaleX(scaleX)
                    .scaleY(scaleY)
                    .translationX(deltaX)
                    .translationY(deltaY)
                    .withEndAction(new Runnable() {
                        @Override
                        public void run() {
                            finish();
                            overridePendingTransition(0, 0);
                        }
                    }).start();
        }
    

    好了,完事

    但是如果应用在产品上的话,你看淘宝或其他app,就会发现要A和B的图片宽高比一定是相同,不然动画是不对的,我这里没有处理。

    相关参考

    Android Shared-Element Transitions for all

    相关文章

      网友评论

        本文标题:低版本实现共享元素动画

        本文链接:https://www.haomeiwen.com/subject/xeafettx.html