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