Jak animować zmianę koloru paska stanu i paska narzędzi (tak jak robi to nowa aplikacja kalendarza)

Nowa aplikacja kalendarza Google ma animację, którą chciałbym zrobić w mojej aplikacji. Podczas tworzenia nowego zdarzenia można wybrać jego kolor. Gdy to zrobisz, pasek stanu i pasek narzędzi zmieni się na ten kolor z okrągłym efektem, który obejmuje oba te kolory.

Oto przykład tego, co chciałbym zrobić:

Kalendarz Google nowy pasek narzędzi i pasek stanu zmiana koloru

Mogę zmienić kolor paska stanu i paska narzędzi, ale jak mogę zastosować efekt okrągłej animacji (lub podobny) do obu z nich, ponieważ kolor jest zmieniłeś się?

Author: Shaun, 2015-01-10

4 answers

Nie wiem, czy dokładnie tak robi aplikacja kalendarza, ale jest wystarczająco blisko dla mnie.

Caveats

  • metoda wykorzystuje metodę ViewAnimationUtils.createCircularReveal wprowadzoną w Lollipop.
  • wymaga znajomości wysokości paska stanu i paska akcji paska narzędzi. Nadal możesz użyć ?attr/actionBarSize dla paska akcji i uzyskać oba dynamicznie, ale dla uproszczenia przyjęłam 56dp dla wysokości paska akcji i 24dp dla wysokości paska stanu.

Ogólne Idea

Ogólna idea polega na ustawieniu paska akcji i paska stanu na przezroczysty. Spowoduje to przesunięcie paska akcji w górę pod paskiem stanu, więc musisz dostosować rozmiar i wypełnienie paska akcji, aby to skompensować. Następnie używasz widoku za nim i ViewAnimationUtils.createCircularReveal, aby odsłonić nowy kolor tła. Potrzebujesz jeszcze jednego widoku, aby pokazać stary kolor tła, ponieważ Widok środkowy ujawnia nowy.

Animacja

Animacja wymaga:

  • przezroczysty pasek narzędzi Pasek czynności , który obejmuje przestrzeń zwykłego paska czynności i paska stanu. Hard-coded wysokość, w tym przypadku, jest 56dp (actionbar) + 24dp (statusbar) = 80dp. Musisz również ustawić górne wypełnienie na 24dp, aby zawartość paska actionbar our znajdowała się pod paskiem stanu.
  • widok środkowy (nazwę Go reveal view ) jest tego samego rozmiaru (wysokość 80dp), ale tuż za paskiem akcji. To będzie Widok ViewAnimationUtils.createCircularReveal działa na.
  • widok z dołu (nazwę Go reveal background view), który jest tego samego rozmiaru co Widok reveal, ale za nim. Ten widok Służy do pokazania starego koloru tła, podczas gdy Widok odsłaniania ujawnia nowy kolor na wierzchu.

Kod

Oto kluczowe fragmenty kodu, których użyłem. Zobacz przykładowy projekt na 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>

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

Główna aktywność.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);
    }
}

Uwagi

  • uważaj na właściwości android:elevation na pasku narzędzi, reveal i reveal widoki tła. Jeśli elewacja jest niższa na pasku narzędzi, Pozostałe zakryją przyciski i tekst.
 37
Author: Shaun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-06 00:07:18

Nie wiem, jak uzyskali efekt ripple, ale możesz mieć płynne przejście koloru obu pasków jednocześnie z następującym kodem.

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);
}
 28
Author: Fernanda Bari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-30 15:43:44

Po wielu badaniach

Znalazłem odpowiedź, której byś chciał.

Ta animacja nazywa się animacją ujawnienia wprowadzoną w API Androida 21.0-lollipop . Niestety nie jest kompatybilny wstecz.

Znalazłem bibliotekę, która robi tę samą animację, ale nie do końca backport, ale pożądany efekt można osiągnąć API 14 z tą biblioteką

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

Thank Ty,

Jeśli chcesz korzystać z tej animacji tylko z lollipop to po prostu google "Android Reveal Animation Colour implementation".

 3
Author: TheAnimatrix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-04 14:18:17

Spróbuj tego, to działa świetnie dla mnie i dostaje taki sam efekt Google Calendar app robi.

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
Author: alonsoapp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-17 16:15:26