web-dev-qa-db-ja.com

ステータスバーとツールバーの色の変化をアニメーション化するには(新しいカレンダーアプリのように)

新しいGoogleカレンダーアプリには、アプリでやりたいアニメーションがあります。新しいイベントを作成するときに、イベントの色を選択できます。すると、ステータスバーとツールバーがその色に変わり、両方を覆う円形の効果が現れます。

これが私がやりたいことの例です:

Google Calendar new event toolbar and statusbar color change

ステータスバーとツールバーの色を変更できますが、色が変更されたときにそれらの両方に円形アニメーション効果(または同様の)を適用するにはどうすればよいですか?

33
Shaun

これがカレンダーアプリの正確な方法かどうかはわかりませんが、私にとっては十分に近いものです。

注意事項

  • このメソッドは、Lollipopで導入されたViewAnimationUtils.createCircularRevealメソッドを使用します。
  • ステータスバーとツールバーのアクションバーの高さを知る必要があります。アクションバーに?attr/actionBarSizeを使用して両方を動的に取得できますが、ここでは簡単にするために、アクションバーの高さを56dp、ステータスバーの高さを24dpと仮定しました。

一般的なアイデア

一般的な考え方は、アクションバーとステータスバーを透明に設定することです。これにより、アクションバーがステータスバーの下に移動するため、アクションバーのサイズとパディングを調整して補正する必要があります。次に、その背後のビューとViewAnimationUtils.createCircularRevealを使用して、新しい背景色を表示します。中央のビューが新しい背景色を表示しているときに古い背景色を表示するには、その背後にもう1つのビューが必要です。

アニメーション

アニメーションに必要なもの:

  • 通常のアクションバーとステータスバーのスペースをカバーする透明なツールバーactionbar。この場合、ハードコーディングされた高さは56dp(アクションバー)+ 24dp(ステータスバー)= 80dpです。また、アクションバーのコンテンツをステータスバーの下に保持するために、上部のパディングを24dpに設定する必要があります。
  • 同じサイズ(80dpの高さ)で、アクションバーのすぐ後ろにある中央のビュー(表示ビューと呼びます)。これは、ViewAnimationUtils.createCircularRevealが作用するビューになります。
  • 下部ビュー(表示背景ビューと呼びます)は、表示ビューと同じサイズですが、その背後にあります。このビューは、古いビューの背景色を表示するためにありますが、表示ビューはその上に新しい色を表示します。

コード

ここに私が使用した主要なコードを示します。 https://github.com/shaun-blake-experiments/example-toolbar-animation のサンプルプロジェクトを参照してください。

activity_main.xml

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    tools:context=".MainActivity">

    <View
        Android:id="@+id/revealBackground"
        Android:layout_width="match_parent"
        Android:layout_height="80dp"
        Android:paddingTop="24dp"
        Android:background="@color/primary"
        Android:elevation="4dp">
    </View>

    <View
        Android:id="@+id/reveal"
        Android:layout_width="match_parent"
        Android:layout_height="80dp"
        Android:paddingTop="24dp"
        Android:background="@color/primary"
        Android:elevation="4dp">
    </View>

    <Toolbar
        Android:id="@+id/appbar"
        Android:layout_width="match_parent"
        Android:layout_height="80dp"
        Android:paddingTop="24dp"
        Android:background="@Android:color/transparent"
        Android:elevation="4dp"
        Android:theme="@style/TranslucentActionBar">
        </Toolbar>

    <ToggleButton
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="Invert Toolbar Colors"
        Android:textOn="Invert Toolbar Colors On"
        Android:textOff="Invert Toolbar Colors Off"
        Android:id="@+id/toggleButton"
        Android:layout_centerVertical="true"
        Android:layout_centerHorizontal="true" />

</RelativeLayout>

styles.xml

<resources>
    <style name="AppTheme" parent="@Android:style/Theme.Material.Light.NoActionBar">
        <item name="Android:windowTranslucentStatus">true</item>
        <item name="Android:windowContentOverlay">@null</item>
    </style>

    <style name="TranslucentActionBar" parent="@Android:style/Widget.Material.ActionBar">
        <item name="Android:textColorPrimary">@color/primary_text_dark_background</item>
    </style>
</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="primary">#2196F3</color>
    <color name="primary_dark">#1976D2</color>
    <color name="primary_light">#BBDEFB</color>
    <color name="accent">#009688</color>
    <color name="primary_text">#DD000000</color>
    <color name="primary_text_dark_background">#FFFFFF</color>
    <color name="secondary_text">#89000000</color>
    <color name="icons">#FFFFFF</color>
    <color name="divider">#30000000</color>
</resources>

MainActivity.Java

package com.example.Android.toolbaranimation;

import Android.animation.Animator;
import Android.animation.AnimatorListenerAdapter;
import Android.app.Activity;
import Android.os.Bundle;
import Android.view.View;
import Android.view.ViewAnimationUtils;
import Android.widget.ToggleButton;
import Android.widget.Toolbar;


public class MainActivity extends Activity {

    private View mRevealView;
    private View mRevealBackgroundView;
    private Toolbar mToolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mToolbar = (Toolbar) findViewById(R.id.appbar);
        mToolbar.setTitle(getString(R.string.app_name));

        mRevealView = findViewById(R.id.reveal);
        mRevealBackgroundView = findViewById(R.id.revealBackground);

        ToggleButton toggleButton = (ToggleButton) findViewById(R.id.toggleButton);
        toggleButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                boolean on = ((ToggleButton) v).isChecked();

                if (on) {
                    animateAppAndStatusBar(R.color.primary, R.color.accent);
                } else {
                    animateAppAndStatusBar(R.color.accent, R.color.primary);
                }
            }
        });

        setActionBar(mToolbar);
    }

    private void animateAppAndStatusBar(int fromColor, final int toColor) {
        Animator animator = ViewAnimationUtils.createCircularReveal(
                mRevealView,
                mToolbar.getWidth() / 2,
                mToolbar.getHeight() / 2, 0,
                mToolbar.getWidth() / 2);

        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                mRevealView.setBackgroundColor(getResources().getColor(toColor));
            }
        });

        mRevealBackgroundView.setBackgroundColor(getResources().getColor(fromColor));
        animator.setStartDelay(200);
        animator.setDuration(125);
        animator.start();
        mRevealView.setVisibility(View.VISIBLE);
    }
}

ノート

  • ツールバーのAndroid:elevationプロパティに注意して、背景ビューを表示および表示します。ツールバーの標高が低い場合、他のボタンはボタンとテキストを覆います。
39
Shaun

それらがどのようにリップル効果を達成したかはわかりませんが、次のコードで両方のバーを同時にスムーズにcolorに移行できます。

private void tintSystemBars() {
    // Initial colors of each system bar.
    final int statusBarColor = getResources().getColor(R.color.status_bar_color);
    final int toolbarColor = getResources().getColor(R.color.toolbar_color);

    // Desired final colors of each bar.
    final int statusBarToColor = getResources().getColor(R.color.status_bar_to_color);
    final int toolbarToColor = getResources().getColor(R.color.toolbar_to_color);

    ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            // Use animation position to blend colors.
            float position = animation.getAnimatedFraction();

            // Apply blended color to the status bar.
            int blended = blendColors(statusBarColor, statusBarToColor, position);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
                getWindow.setStatusBarColor(blended);
            }

            // Apply blended color to the ActionBar.
            blended = blendColors(toolbarColor, toolbarToColor, position);
            ColorDrawable background = new ColorDrawable(blended);
            getSupportActionBar().setBackgroundDrawable(background);
        }
    });

    anim.setDuration(500).start();
}

private int blendColors(int from, int to, float ratio) {
    final float inverseRatio = 1f - ratio;

    final float r = Color.red(to) * ratio + Color.red(from) * inverseRatio;
    final float g = Color.green(to) * ratio + Color.green(from) * inverseRatio;
    final float b = Color.blue(to) * ratio + Color.blue(from) * inverseRatio;

    return Color.rgb((int) r, (int) g, (int) b);
}
31
Fernanda Bari

大量の研究の後、

あなたが望む答えを見つけました。

このアニメーションは、21.0 Android API-Lollipopで導入された公開アニメーションと呼ばれます。残念ながら、下位互換性はありません。

私は同じバックグラウンドではないアニメーションを明らかにするライブラリを見つけましたが、あなたが望む効果はこのライブラリでAPI 14以降に達成することができます

https://github.com/markushi/Android-ui

ありがとうございました、

Lollipopのみでこのアニメーションを使用したい場合は、「Android Reveal Color Animation implementation」をグーグルで検索してください。

4
TheAnimatrix

これを試してみてください、それは私にとってはうまく機能し、Googleカレンダーアプリと同じ効果が得られます。

private void reveal(CollapsingToolbarLayout toolbarLayout, int colorPrimary, int colorPrimaryDark){
    // get the center for the clipping circle
    int cx = toolbarLayout.getWidth() / 2;
    int cy = toolbarLayout.getHeight() / 2;

    // get the final radius for the clipping circle
    float finalRadius = (float) Math.hypot(cx, cy);

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

    // make the view visible and start the animation
    toolbarLayout.setBackgroundColor(colorPrimary);
    anim.start();
    Window window = getWindow();
    window.setStatusBarColor(colorPrimaryDark);
    toolbarLayout.setContentScrimColor(colorPrimary);
}
3
alonsoapp