1 /*
2 * Copyright 2014 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 
17 package com.example.android.interpolator;
18 
19 import android.animation.ObjectAnimator;
20 import android.graphics.Path;
21 import android.os.Bundle;
22 import android.support.v4.app.Fragment;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.view.animation.AnimationUtils;
27 import android.view.animation.Interpolator;
28 import android.widget.ArrayAdapter;
29 import android.widget.Button;
30 import android.widget.SeekBar;
31 import android.widget.Spinner;
32 import android.widget.TextView;
33 
34 import com.example.android.common.logger.Log;
35 
36 /**
37  * This sample demonstrates the use of animation interpolators and path animations for
38  * Material Design.
39  * It shows how an {@link android.animation.ObjectAnimator} is used to animate two properties of a
40  * view (scale X and Y) along a path.
41  */
42 public class InterpolatorFragment extends Fragment {
43 
44     /**
45      * View that is animated.
46      */
47     private View mView;
48     /**
49      * Spinner for selection of interpolator.
50      */
51     private Spinner mInterpolatorSpinner;
52     /**
53      * SeekBar for selection of duration of animation.
54      */
55     private SeekBar mDurationSeekbar;
56     /**
57      * TextView that shows animation selected in SeekBar.
58      */
59     private TextView mDurationLabel;
60 
61     /**
62      * Interpolators used for animation.
63      */
64     private Interpolator mInterpolators[];
65     /**
66      * Path for in (shrinking) animation, from 100% scale to 20%.
67      */
68     private Path mPathIn;
69     /**
70      * Path for out (growing) animation, from 20% to 100%.
71      */
72     private Path mPathOut;
73 
74     /**
75      * Set to true if View is animated out (is shrunk).
76      */
77     private boolean mIsOut = false;
78 
79     /**
80      * Default duration of animation in ms.
81      */
82     private static final int INITIAL_DURATION_MS = 750;
83 
84     /**
85      * String used for logging.
86      */
87     public static final String TAG = "InterpolatorplaygroundFragment";
88 
InterpolatorFragment()89     public InterpolatorFragment() {
90         // Required empty public constructor
91     }
92 
93 
94     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)95     public View onCreateView(LayoutInflater inflater, ViewGroup container,
96                              Bundle savedInstanceState) {
97 
98         // Inflate the fragment_animation layout
99         View v = inflater.inflate(R.layout.interpolator_fragment, container, false);
100 
101         // Set up the 'animate' button, when it is clicked the view is animated with the options
102         // selected: the Interpolator, duration and animation path
103         Button button = (Button) v.findViewById(R.id.animateButton);
104         button.setOnClickListener(new View.OnClickListener() {
105             @Override
106             public void onClick(View view) {
107                 // Interpolator selected in the spinner
108                 Interpolator interpolator = mInterpolators[mInterpolatorSpinner.getSelectedItemPosition()];
109                 // Duration selected in SeekBar
110                 long duration = mDurationSeekbar.getProgress();
111                 // Animation path is based on whether animating in or out
112                 Path path = mIsOut ? mPathIn : mPathOut;
113 
114                 // Log animation details
115                 Log.i(TAG, String.format("Starting animation: [%d ms, %s, %s]",
116                         duration, (String) mInterpolatorSpinner.getSelectedItem(),
117                         ((mIsOut) ? "Out (growing)" : "In (shrinking)")));
118 
119                 // Start the animation with the selected options
120                 startAnimation(interpolator, duration, path);
121 
122                 // Toggle direction of animation (path)
123                 mIsOut = !mIsOut;
124             }
125         });
126 
127         // Get the label to display the selected duration
128         mDurationLabel = (TextView) v.findViewById(R.id.durationLabel);
129 
130         // Initialize Interpolators programmatically by loading them from their XML definitions
131         // provided by the framework.
132         mInterpolators = new Interpolator[]{
133                 new AnimationUtils().loadInterpolator(getActivity(),
134                         android.R.interpolator.linear),
135                 new AnimationUtils().loadInterpolator(getActivity(),
136                         android.R.interpolator.fast_out_linear_in),
137                 new AnimationUtils().loadInterpolator(getActivity(),
138                         android.R.interpolator.fast_out_slow_in),
139                 new AnimationUtils().loadInterpolator(getActivity(),
140                         android.R.interpolator.linear_out_slow_in)
141         };
142 
143         // Load names of interpolators from a resource
144         String[] interpolatorNames = getResources().getStringArray(R.array.interpolator_names);
145 
146         // Set up the Spinner with the names of interpolators
147         mInterpolatorSpinner = (Spinner) v.findViewById(R.id.interpolatorSpinner);
148         ArrayAdapter<String> spinnerAdapter =
149                 new ArrayAdapter<String>(getActivity(),
150                         android.R.layout.simple_spinner_dropdown_item, interpolatorNames);
151         mInterpolatorSpinner.setAdapter(spinnerAdapter);
152 
153         // Set up SeekBar that defines the duration of the animation
154         mDurationSeekbar = (SeekBar) v.findViewById(R.id.durationSeek);
155 
156         // Register listener to update the text label when the SeekBar value is updated
157         mDurationSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
158             @Override
159             public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
160                 mDurationLabel.setText(getResources().getString(R.string.animation_duration, i));
161             }
162 
163             @Override
164             public void onStartTrackingTouch(SeekBar seekBar) {
165             }
166 
167             @Override
168             public void onStopTrackingTouch(SeekBar seekBar) {
169             }
170         });
171 
172         // Set initial progress to trigger SeekBarChangeListener and update UI
173         mDurationSeekbar.setProgress(INITIAL_DURATION_MS);
174 
175         // Get the view that will be animated
176         mView = v.findViewById(R.id.square);
177 
178         // The following Path definitions are used by the ObjectAnimator to scale the view.
179 
180         // Path for 'in' animation: growing from 20% to 100%
181         mPathIn = new Path();
182         mPathIn.moveTo(0.2f, 0.2f);
183         mPathIn.lineTo(1f, 1f);
184 
185         // Path for 'out' animation: shrinking from 100% to 20%
186         mPathOut = new Path();
187         mPathOut.moveTo(1f, 1f);
188         mPathOut.lineTo(0.2f, 0.2f);
189         return v;
190     }
191 
192     /**
193      * Start an animation on the sample view.
194      * The view is animated using an {@link android.animation.ObjectAnimator} on the
195      * {@link View#SCALE_X} and {@link View#SCALE_Y} properties, with its animation based on a path.
196      * The only two paths defined here ({@link #mPathIn} and {@link #mPathOut}) scale the view
197      * uniformly.
198      *
199      * @param interpolator The interpolator to use for the animation.
200      * @param duration     Duration of the animation in ms.
201      * @param path         Path of the animation
202      * @return The ObjectAnimator used for this animation
203      * @see android.animation.ObjectAnimator#ofFloat(Object, String, String, android.graphics.Path)
204      */
startAnimation(Interpolator interpolator, long duration, Path path)205     public ObjectAnimator startAnimation(Interpolator interpolator, long duration, Path path) {
206         // This ObjectAnimator uses the path to change the x and y scale of the mView object.
207         ObjectAnimator animator = ObjectAnimator.ofFloat(mView, View.SCALE_X, View.SCALE_Y, path);
208 
209         // Set the duration and interpolator for this animation
210         animator.setDuration(duration);
211         animator.setInterpolator(interpolator);
212 
213         animator.start();
214 
215         return animator;
216     }
217 
218     /**
219      * Return the array of loaded Interpolators available in this Fragment.
220      *
221      * @return Interpolators
222      */
getInterpolators()223     public Interpolator[] getInterpolators() {
224         return mInterpolators;
225     }
226 
227     /**
228      * Return the animation path for the 'in' (shrinking) animation.
229      *
230      * @return
231      */
getPathIn()232     public Path getPathIn() {
233         return mPathIn;
234     }
235 
236     /**
237      * Return the animation path for the 'out' (growing) animation.
238      *
239      * @return
240      */
getPathOut()241     public Path getPathOut() {
242         return mPathOut;
243     }
244 }