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