1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.example.android.support.transition.widget;
18
19import android.animation.Animator;
20import android.animation.ArgbEvaluator;
21import android.animation.ValueAnimator;
22import android.graphics.drawable.ColorDrawable;
23import android.graphics.drawable.Drawable;
24import android.support.annotation.NonNull;
25import android.support.annotation.Nullable;
26import android.support.transition.Transition;
27import android.support.transition.TransitionValues;
28import android.view.View;
29import android.view.ViewGroup;
30
31/**
32 * A sample implementation of support {@link Transition}.
33 */
34public class ChangeColor extends Transition {
35
36    /** Key to store a color value in TransitionValues object */
37    private static final String PROPNAME_BACKGROUND = "transitiondemos:change_color:background";
38
39    /**
40     * Convenience method: Add the background Drawable property value
41     * to the TransitionsValues.value Map for a target.
42     */
43    private void captureValues(TransitionValues values) {
44        // Capture the property values of views for later use
45        values.values.put(PROPNAME_BACKGROUND, values.view.getBackground());
46    }
47
48    @Override
49    public void captureEndValues(@NonNull TransitionValues transitionValues) {
50        captureValues(transitionValues);
51    }
52
53    @Override
54    public void captureStartValues(@NonNull TransitionValues transitionValues) {
55        captureValues(transitionValues);
56    }
57
58    // Create an animation for each target that is in both the starting and ending Scene. For each
59    // pair of targets, if their background property value is a color (rather than a graphic),
60    // create a ValueAnimator based on an ArgbEvaluator that interpolates between the starting and
61    // ending color. Also create an update listener that sets the View background color for each
62    // animation frame
63    @Nullable
64    @Override
65    public Animator createAnimator(@NonNull ViewGroup sceneRoot,
66                                   @Nullable TransitionValues startValues,
67                                   @Nullable TransitionValues endValues) {
68        // This transition can only be applied to views that are on both starting and ending scenes.
69        if (null == startValues || null == endValues) {
70            return null;
71        }
72        // Store a convenient reference to the target. Both the starting and ending layout have the
73        // same target.
74        final View view = endValues.view;
75        // Store the object containing the background property for both the starting and ending
76        // layouts.
77        Drawable startBackground = (Drawable) startValues.values.get(PROPNAME_BACKGROUND);
78        Drawable endBackground = (Drawable) endValues.values.get(PROPNAME_BACKGROUND);
79        // This transition changes background colors for a target. It doesn't animate any other
80        // background changes. If the property isn't a ColorDrawable, ignore the target.
81        if (startBackground instanceof ColorDrawable && endBackground instanceof ColorDrawable) {
82            ColorDrawable startColor = (ColorDrawable) startBackground;
83            ColorDrawable endColor = (ColorDrawable) endBackground;
84            // If the background color for the target in the starting and ending layouts is
85            // different, create an animation.
86            if (startColor.getColor() != endColor.getColor()) {
87                // Create a new Animator object to apply to the targets as the transitions framework
88                // changes from the starting to the ending layout. Use the class ValueAnimator,
89                // which provides a timing pulse to change property values provided to it. The
90                // animation runs on the UI thread. The Evaluator controls what type of
91                // interpolation is done. In this case, an ArgbEvaluator interpolates between two
92                // #argb values, which are specified as the 2nd and 3rd input arguments.
93                ValueAnimator animator = ValueAnimator.ofObject(new ArgbEvaluator(),
94                        startColor.getColor(), endColor.getColor());
95                // Add an update listener to the Animator object.
96                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
97                    @Override
98                    public void onAnimationUpdate(ValueAnimator animation) {
99                        Object value = animation.getAnimatedValue();
100                        // Each time the ValueAnimator produces a new frame in the animation, change
101                        // the background color of the target. Ensure that the value isn't null.
102                        if (null != value) {
103                            view.setBackgroundColor((Integer) value);
104                        }
105                    }
106                });
107                // Return the Animator object to the transitions framework. As the framework changes
108                // between the starting and ending layouts, it applies the animation you've created.
109                return animator;
110            }
111        }
112        // For non-ColorDrawable backgrounds, we just return null, and no animation will take place.
113        return null;
114    }
115
116}
117