如何设置状态栏和工具栏的颜色更改动画(就像新的日历应用程序一样)

时间:2015-01-10 02:41:45

标签: android android-animation android-5.0-lollipop

新的Google日历应用有我想在我的应用中执行的动画。创建新事件时,您可以选择事件的颜色。执行此操作时,状态栏和工具栏将更改为该颜色,并具有覆盖它们的圆形效果。

以下是我要做的事情的一个例子:

Google Calendar new event toolbar and statusbar color change

我可以更改状态栏和工具栏的颜色,但是当颜色发生变化时,如何将圆形动画效果(或类似效果)应用于它们?

4 个答案:

答案 0 :(得分:38)

我不知道这是不是日历应用程序的确切方式,但它对我来说足够接近。

注意事项

  • 该方法使用Lollipop中引入的ViewAnimationUtils.createCircularReveal方法。
  • 需要知道状态栏和工具栏操作栏的高度。您仍然可以将[{1}}用于操作栏并动态获取,但为了简单起见,我假设?attr/actionBarSize表示操作栏高度,56dp表示状态栏高度。

一般理念

一般的想法是将操作栏和状态栏设置为透明。这会将操作栏移到状态栏下方,因此您必须调整操作栏的大小和填充以进行补偿。然后使用它后面的视图和24dp来显示新的背景颜色。你需要一个更多的视图来显示旧的背景颜色,因为中间视图显示了新的背景颜色。

动画

动画需要:

  • 透明工具栏操作栏,涵盖常规操作栏和状态栏的空间。在这种情况下,硬编码高度为56dp(动作栏)+ 24dp(状态栏)= 80dp。您还需要将顶部填充设置为24dp,以将动作栏内容保留在状态栏下。
  • 中间视图(我将其称为显示视图),其大小相同(高度为80dp),但位于操作栏后面。这将是ViewAnimationUtils.createCircularReveal作用的视图。
  • 底视图(我将其称为显示背景视图),其大小与显示视图相同但在其后面。此视图用于显示旧的背景颜色,而显示视图则显示其上方的新颜色。

代码

以下是我使用的关键代码。请参阅https://github.com/shaun-blake-experiments/example-toolbar-animation上的示例项目。

activity_main.xml中

ViewAnimationUtils.createCircularReveal

styles.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>

colors.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>

MainActivity.java

<?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>

注释

  • 注意工具栏上的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); } } 属性,显示和显示背景视图。如果工具栏上的高程较低,则其他高程将覆盖按钮和文本。

答案 1 :(得分:30)

我不知道它们是如何实现涟漪效果的,但您可以使用以下代码同时进行两个条形的平滑颜色过渡。

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);
}

答案 2 :(得分:4)

经过大量的研究,

我找到了你想要的答案。

这个动画被称为21.0 Android API - 棒棒糖中引入的揭示动画。不幸的是,它不向后兼容。

我找到了一个同样可以显示动画但不完全是反向移动的库,但是你想要的效果可以通过这个库实现API 14以后

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

谢谢,

如果您热衷于仅使用棒棒糖这个动画,那么只需谷歌“Android Reveal Color Animation implementation”。

答案 3 :(得分:3)

试试这个,它对我很有用,它可以获得与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);
}