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 }