web-dev-qa-db-ja.com

円形は新しい活動のための移行を明らかにする

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が循環的に表示されるようにします。

67
Ishaan Garg

結果なしで半日ソリューションを探した後、私は独自の実装を思いつきました。ルートレイアウトが一致する透明なアクティビティを使用しています。ルートレイアウトは、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"
        />

次に、アクティビティのレイアウトを宣言しました(NavDrawerを使用できるように、DrawerLayoutを選択しました。すべてのレイアウトがここで機能するはずです)。

<Android.support.v4.widget.DrawerLayout
    Android:id="@+id/drawer_layout"
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    >

    <FrameLayout
        Android:id="@+id/root_layout"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        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>
83
Stefan Medack

CircularRevealアニメーションを逆にするには、startRadiusendRadius引数を入れ替えます。また、AnimatorListenerをセットアップする必要があり、onAnimationEnd()コールバックメソッドでfinishAfterTransition()を呼び出すことができます。これは、up navigationを押すか、back buttonをクリックした場合に使用します。

7
toobsco42

退出アクティビティの循環表示を元に戻す場合は、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();
    }
}
7
jayasoo
6
TeeTracker

サークルビューを描画する必要があります。その後、アニメーションを作成する必要があります。

サークルビューの作成:

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_width="300dp"
    Android:layout_height="300dp" />

そして最後にアニメーションを開始します:

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

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