具有半径的CardView上的共享元素转换

时间:2017-02-16 12:55:25

标签: android android-animation android-cardview android-transitions shared-element-transition

我已经解决了这个问题好几个星期了,我仍然无法解决这个问题。

所以,我有一个包含带有ImageView的LinearLayout的CardView。

without radius

没有该半径,共享元素转换无缝地工作。但是,当我将半径(app:cardCornerRadius =" 25dp")添加到CardView时,共享元素转换看起来很难看,因为首先删除半径然后启动动画。 / p>

with radius transition

第一种方法:ObjectAnimator

我创建了ObjectAnimator来为卡上的半径值设置动画,并在动画结束后开始转换。

ObjectAnimator animator = ObjectAnimator
            .ofFloat(view, "radius", AppUtil.dpAsPixel(this, 25), 0);
animator.setDuration(150);
animator.addListener( // start new Activity with Transition );
animator.start();

这样可行,但它看起来不太好,因为转换在开始转换之前等待动画完成。我需要的是半径是在转换到新Activity时的动画(类似于TransitionSet中的ORDERING_TOGETHER)。

第二种方法 - ChangeImageTransform

我已阅读StackOverflow post以使用转化类,如ChangeImageTransform和ChangeBounds。

我确实定义了我的应用主题,就像它建议的那样(my_transition包含ChangeImageTransform transitionSet)

<item name="android:windowSharedElementEnterTransition">@transition/my_transition</item>
<item name="android:windowSharedElementExitTransition">@transition/my_transition</item>

但它不起作用..

第三种方法 - 天真

我的最后一次尝试是强制目标ImageView的半径也是25dp。因为目标ImageView可能是方形的,因此可能我的CardView被转换为方形,但正如您所猜测的那样,它不起作用。

第4种方法 - 不使用CardView

如您所见,我使用企鹅图像并使用CardView制作半径。我可以使用图像转换使图像四舍五入,但我仍然不认为这是创建共享元素转换的正确方法..

这是我的问题,有没有办法让CardView半径的共享元素转换工作而不首先删除半径?

4 个答案:

答案 0 :(得分:10)

我终于能够解决它了。对于那些感兴趣的人,请参见:

为什么在开始转换之前删除半径?因为目标ImageView没有任何半径。

<强> activity_detail.xml

<ImageView
    android:id="@+id/iv_image_cover"
    android:layout_width="match_parent"
    android:layout_height="250dp"
    android:scaleType="centerCrop"
    android:src="@{animal.imageRes}"
    android:transitionName="animalImage"
    tools:src="@drawable/acat"
/>

当我使用没有半径的CardView时,它并不显着,但它实际上已转变为目标共享视图。

  1. 要实现半径到无半径转换,您必须将目标共享视图设置为四舍五入。我只需使用卡片视图(半径)包裹它。
  2. <强> activity_detail.xml

    <android.support.v7.widget.CardView
        android:id="@+id/card"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:transitionName="card"
        app:cardCornerRadius="25dp"
    >
    
        <ImageView
            android:id="@+id/iv_image_cover"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:scaleType="centerCrop"
            android:src="@{animal.imageRes}"
            android:transitionName="animalImage"
            tools:src="@drawable/acat"
        />
    
    </android.support.v7.widget.CardView>
    
    1. 请务必将makeSceneTransition更改为使用&#34; card&#34;而不是&#34; animalImage&#34;
    2. <强> ListActivity.class

      ActivityOptionsCompat option = ActivityOptionsCompat
      .makeSceneTransitionAnimation(ListActivity.this, cardView, "card");
      
      startActivity(intent, option.toBundle());
      
      1. 在DetailActivity中,您可以在转换开始时启动半径动画。
      2. <强> DetailActivity.java

        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            getWindow().getSharedElementEnterTransition()
                .addListener(new Transition.TransitionListener() {
                    @Override
                    public void onTransitionStart(Transition transition) {
                        ObjectAnimator animator = ObjectAnimator
                            .ofFloat(activityDetailBinding.card, "radius", 0);
                        animator.setDuration(250);
                        animator.start();
                    }
                });
        }
        
        1. 享受平稳过渡
        2. final animation

          注意:layoutactivities

          的要点

答案 1 :(得分:1)

根据Ovidiu的回答,这是一个可以使角动画的工作过渡

https://gist.github.com/StefanDeBruijn/d45807d386af0e066a03186fe00366e8

这可以通过编程方式添加到输入的共享转换集中,也可以通过xml添加:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <transitionSet>
        <targets>
            <target android:targetId="@id/backdrop" />
        </targets>
        <!-- Custom transition to take care of rounded corner to square corners transition -->
        <transition
            class=".ChangeOutlineRadius"
            app:endRadius="@dimen/square_corner_radius"
            app:startRadius="@dimen/default_corner_radius" />
        <!-- Default shared element transitions -->
        <changeBounds />
        <changeTransform />
        <changeClipBounds />
        <changeImageTransform />
    </transitionSet>
</transitionSet>

别忘了添加到您的attrs.xml:

   <declare-styleable name="ChangeOutlineRadius">
        <attr name="startRadius" format="dimension" />
        <attr name="endRadius" format="dimension" />
    </declare-styleable>

答案 2 :(得分:1)

我在这里尝试了所有解决方案,但没有任何效果。我需要从 asp.net mvc core 比例类型转到 centerInside。这在使用建议在 cardview 上应用动画的解决方案时产生了问题。 (在这种情况下,比例类型没有动画)。

所以为了解决这个问题,在父 ImageView 本身,我应用了一个圆角:

fitCenter

不需要做任何其他事情,Transition Animation API 会处理剩下的事情。

和平。 :)

答案 3 :(得分:0)

我无法使用 Fragment 共享元素过渡。 CardView的角半径将在动画过程中被忽略。这是行得通的:

fragment2.setEnterSharedElementCallback(new SharedElementCallback() {
    @Override
    public void onSharedElementStart(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {}

    @Override
    public void onSharedElementEnd(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
        ImageView sharedImageView = null;

        for (View view : sharedElements) {
            if (view instanceof ImageView) {
                sharedImageView = (ImageView) view;
                break;
            }
        }

        if (sharedImageView != null) {
            sharedImageView.setClipToOutline(true);

            ObjectAnimator.ofInt(sharedImageView, new Property<ImageView, Integer>(Integer.class, "outlineRadius") {
                @Override
                public Integer get(ImageView object) {
                    return 0;
                }

                @Override
                public void set(ImageView object, final Integer value) {
                    object.setOutlineProvider(new ViewOutlineProvider() {
                        @Override
                        public void getOutline(View view, Outline outline) {
                            outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), value);
                        }
                    });
                }
            }, 150, 0).setDuration(duration).start();
        }
    }

    @Override
    public void onRejectSharedElements(List<View> rejectedSharedElements) {}

    @Override
    public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {}
});

基本上,ImageView本身不对CardView的圆角进行动画处理,而是具有自己的圆角,并对其进行动画处理。

ImageView的角使用ViewOutlineProvider进行圆角处理,并且在播放共享元素过渡时,可以使用ObjectAnimator设置角半径的动画。请注意,还需要在ImageView上调用setClipToOutline(true),否则将不会修剪拐角。

将使用所有共享元素的列表调用回调的onSharedElementEnd方法。请注意,我的示例代码只处理了要共享的ImageView之一的角动画。如果您的过渡共享多个ImageView,则还需要考虑这些。

还请注意,由于某种原因,在播放反向过渡时也会调用相同的回调。

经过一些努力,这可以变成常规的过渡,您只需将其添加到一组共享元素过渡中,即可自动确定如何处理共享元素。