新活动的圆形展示过渡

Posted

技术标签:

【中文标题】新活动的圆形展示过渡【英文标题】:Circular reveal transition for new activity 【发布时间】:2015-09-06 15:47:41 【问题描述】:

根据https://developer.android.com/training/material/animations.html

ViewAnimationUtils.createCircularReveal() 方法使您能够 为剪切圆设置动画以显示或隐藏视图。

使用此效果显示以前不可见的视图:

// previously invisible view
View myView = findViewById(R.id.my_view);

// get the center for the clipping circle
int cx = (myView.getLeft() + myView.getRight()) / 2;
int cy = (myView.getTop() + myView.getBottom()) / 2;

// get the final radius for the clipping circle
int finalRadius = Math.max(myView.getWidth(), myView.getHeight());

// create the animator for this view (the start radius is zero)
Animator anim =
    ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);

// make the view visible and start the animation
myView.setVisibility(View.VISIBLE);
anim.start();

这是为了显示一个视图。我如何使用它来循环显示整个活动,而没有任何共享元素?

具体来说,我希望我的 searchActivity 从工具栏中的搜索操作按钮循环显示。

【问题讨论】:

不。不再积极寻找它。 【参考方案1】:

找了半天没有结果的解决方案,我想出了一个自己的实现。我正在使用具有匹配根布局的透明活动。 根布局是一个视图,然后可以使用createCircularReveal() 显示。

我的代码如下所示:

styles.xml 中的主题定义

<style name="Theme.Transparent" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
    <item name="android:windowBackground">@android:color/transparent</item>
</style>

AndroidManifest.xml 中的活动定义

<activity
        android:name=".ui.CircularRevealActivity"
        android:theme="@style/Theme.Transparent"
        android:launchMode="singleTask"
        />

然后我为我的活动声明了一个布局(我选择了 DrawerLayout,这样我就可以拥有一个 NavDrawer。每个布局都应该在这里工作。)

<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    >

    <FrameLayout
        android:id="@+id/root_layout"
        android:layout_
        android:layout_
        android:background="@color/honey_melon"
        >

        <!-- Insert your actual layout here -->

    </FrameLayout>

</android.support.v4.widget.DrawerLayout>

重要的是 ID 为 root_layout 的 FrameLayout。此视图将在活动中展示。

最后我实现了CircularRevealActivity并覆盖了onCreate()

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    overridePendingTransition(R.anim.do_not_move, R.anim.do_not_move);

    setContentView(R.layout.activity_reveal_circular);

    if (savedInstanceState == null) 
        rootLayout.setVisibility(View.INVISIBLE);

        ViewTreeObserver viewTreeObserver = rootLayout.getViewTreeObserver();
        if (viewTreeObserver.isAlive()) 
            viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 
                @Override
                public void onGlobalLayout() 
                    circularRevealActivity();
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) 
                        rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                     else 
                        rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                     
                
            );
        
    

circularRevealActivity() 放入OnGlobalLayoutListener 很重要,因为需要为动画绘制视图。

circularRevealActivity() 好像是Ishaan的提议:

private void circularRevealActivity() 

    int cx = rootLayout.getWidth() / 2;
    int cy = rootLayout.getHeight() / 2;

    float finalRadius = Math.max(rootLayout.getWidth(), rootLayout.getHeight());

    // create the animator for this view (the start radius is zero)
    Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, 0, finalRadius);
    circularReveal.setDuration(1000);

    // make the view visible and start the animation
    rootLayout.setVisibility(View.VISIBLE);
    circularReveal.start();

编辑 1

添加了R.anim.do_not_move 的定义。但是,如果您的设计没有为活动指定默认转换,它也应该在没有该行的情况下工作。告诉我

R.anim.do_not_move:

<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
    android:fromYDelta="0"
    android:toYDelta="0"
    android:duration="@android:integer/config_mediumAnimTime"
    />
</set>

【讨论】:

感谢您提供如此详尽的答案。它对你有用吗?这周我会试一试。 工作对我来说就像一个魅力。我只是觉得应该可以在不将两个活动合并为一个的情况下进行此循环揭示...如果有问题请告诉我。 效果很好。我改变了 cx 和 cy 值来改变原点 R.anim.do_not_move 的定义是什么? @StefanMedack 你应该在onGlobalLayout() 中添加getViewTreeObserver().removeGlobalOnLayoutListener(this);。这避免了多次跟注而导致双重显示。在这里工作。【参考方案2】:

如果您想在离开活动时反转循环显示,请对 onBackPressed() 使用以下修改。

@Override
public void onBackPressed() 

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
        int cx = rootLayout.getWidth();
        int cy = 0;
        float finalRadius = Math.max(rootLayout.getWidth(), rootLayout.getHeight());
        Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, finalRadius, 0);

        circularReveal.addListener(new Animator.AnimatorListener() 
            @Override
            public void onAnimationStart(Animator animator) 

            

            @Override
            public void onAnimationEnd(Animator animator) 
                rootLayout.setVisibility(View.INVISIBLE);
                finish();
            

            @Override
            public void onAnimationCancel(Animator animator) 

            

            @Override
            public void onAnimationRepeat(Animator animator) 

            
        );
        circularReveal.setDuration(400);
        circularReveal.start();
    else
        super.onBackPressed();
    

【讨论】:

【参考方案3】:

要反转CircularReveal 动画,请交换startRadiusendRadius 参数。您还需要设置一个AnimatorListener,并且在onAnimationEnd() 回调方法中可以调用finishAfterTransition()。这是在您按下up navigation 或单击back button 时使用的。

【讨论】:

你应该详细说一下如何实现反向动画。【参考方案4】:

我认为你可以使用ActivityOptionsCompat.makeClipRevealAnimation

[https://developer.android.com/reference/android/support/v4/app/ActivityOptionsCompat.html#makeClipRevealAnimation(android.view.View, int, int, int, int)](https://developer.android.com/reference/android/support/v4/app/ActivityOptionsCompat.html#makeClipRevealAnimation(android.view.View, int, int, int, int))

【讨论】:

仅适用于 APi 23+,否则默认为标准动画 无论如何要使用这个后退按钮回到以前的活动?【参考方案5】:

你必须绘制圆形视图,然后你应该为它创建一个动画。

创建圆形视图:

public class Circle extends View 

    private static final int START_ANGLE_POINT = 90;

    private final Paint paint;
    private final RectF rect;

    private float angle;

    public Circle(Context context, AttributeSet attrs) 
        super(context, attrs);

        final int strokeWidth = 40;

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(strokeWidth);
        //Circle color
        paint.setColor(Color.RED);

        //size 200x200 example
        rect = new RectF(strokeWidth, strokeWidth, 200 + strokeWidth, 200 + strokeWidth);

        //Initial Angle (optional, it can be zero)
        angle = 120;
    

    @Override
    protected void onDraw(Canvas canvas) 
        super.onDraw(canvas);
        canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint);
    

    public float getAngle() 
        return angle;
    

    public void setAngle(float angle) 
        this.angle = angle;
    

创建动画类来设置新的角度:

public class CircleAngleAnimation extends Animation 

    private Circle circle;

    private float oldAngle;
    private float newAngle;

    public CircleAngleAnimation(Circle circle, int newAngle) 
        this.oldAngle = circle.getAngle();
        this.newAngle = newAngle;
        this.circle = circle;
    

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation transformation) 
        float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime);

        circle.setAngle(angle);
        circle.requestLayout();
    

将圆圈放入您的布局中:

<com.package.Circle
    android:id="@+id/circle"
    android:layout_
    android:layout_ />

最后开始动画:

Circle circle = (Circle) findViewById(R.id.circle);

CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240);
animation.setDuration(1000);
circle.startAnimation(animation);

【讨论】:

这不是用户问的问题,但无论如何这对我有很大帮助

以上是关于新活动的圆形展示过渡的主要内容,如果未能解决你的问题,请参考以下文章

在 Spritekit 中扩展圆形切口过渡效果

将 ViewController 缩小为圆形过渡 - swift

如何知道一项活动是不是在没有过渡的情况下开始?

活动过渡黑屏

Android 共享元素转换:将 ImageView 从圆形转换为矩形,然后再转换回来

切换活动时如何添加过渡?