AnimationUtils.java revision a18a86b43e40e3c15dcca0ae0148d641be9b25fe
1/* 2 * Copyright (C) 2007 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 android.view.animation; 18 19import org.xmlpull.v1.XmlPullParser; 20import org.xmlpull.v1.XmlPullParserException; 21 22import android.content.Context; 23import android.content.res.XmlResourceParser; 24import android.content.res.Resources.NotFoundException; 25import android.util.AttributeSet; 26import android.util.Xml; 27import android.os.SystemClock; 28 29import java.io.IOException; 30 31/** 32 * Defines common utilities for working with animations. 33 * 34 */ 35public class AnimationUtils { 36 37 /** 38 * These flags are used when parsing AnimatorSet objects 39 */ 40 private static final int TOGETHER = 0; 41 private static final int SEQUENTIALLY = 1; 42 43 44 /** 45 * Returns the current animation time in milliseconds. This time should be used when invoking 46 * {@link Animation#setStartTime(long)}. Refer to {@link android.os.SystemClock} for more 47 * information about the different available clocks. The clock used by this method is 48 * <em>not</em> the "wall" clock (it is not {@link System#currentTimeMillis}). 49 * 50 * @return the current animation time in milliseconds 51 * 52 * @see android.os.SystemClock 53 */ 54 public static long currentAnimationTimeMillis() { 55 return SystemClock.uptimeMillis(); 56 } 57 58 /** 59 * Loads an {@link Animation} object from a resource 60 * 61 * @param context Application context used to access resources 62 * @param id The resource id of the animation to load 63 * @return The animation object reference by the specified id 64 * @throws NotFoundException when the animation cannot be loaded 65 */ 66 public static Animation loadAnimation(Context context, int id) 67 throws NotFoundException { 68 69 XmlResourceParser parser = null; 70 try { 71 parser = context.getResources().getAnimation(id); 72 return createAnimationFromXml(context, parser); 73 } catch (XmlPullParserException ex) { 74 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 75 Integer.toHexString(id)); 76 rnf.initCause(ex); 77 throw rnf; 78 } catch (IOException ex) { 79 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 80 Integer.toHexString(id)); 81 rnf.initCause(ex); 82 throw rnf; 83 } finally { 84 if (parser != null) parser.close(); 85 } 86 } 87 88 private static Animation createAnimationFromXml(Context c, XmlPullParser parser) 89 throws XmlPullParserException, IOException { 90 91 return createAnimationFromXml(c, parser, null, Xml.asAttributeSet(parser)); 92 } 93 94 private static Animation createAnimationFromXml(Context c, XmlPullParser parser, 95 AnimationSet parent, AttributeSet attrs) throws XmlPullParserException, IOException { 96 97 Animation anim = null; 98 99 // Make sure we are on a start tag. 100 int type; 101 int depth = parser.getDepth(); 102 103 while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 104 && type != XmlPullParser.END_DOCUMENT) { 105 106 if (type != XmlPullParser.START_TAG) { 107 continue; 108 } 109 110 String name = parser.getName(); 111 112 if (name.equals("set")) { 113 anim = new AnimationSet(c, attrs); 114 createAnimationFromXml(c, parser, (AnimationSet)anim, attrs); 115 } else if (name.equals("alpha")) { 116 anim = new AlphaAnimation(c, attrs); 117 } else if (name.equals("scale")) { 118 anim = new ScaleAnimation(c, attrs); 119 } else if (name.equals("rotate")) { 120 anim = new RotateAnimation(c, attrs); 121 } else if (name.equals("translate")) { 122 anim = new TranslateAnimation(c, attrs); 123 } else { 124 throw new RuntimeException("Unknown animation name: " + parser.getName()); 125 } 126 127 if (parent != null) { 128 parent.addAnimation(anim); 129 } 130 } 131 132 return anim; 133 134 } 135 136 public static LayoutAnimationController loadLayoutAnimation(Context context, int id) 137 throws NotFoundException { 138 139 XmlResourceParser parser = null; 140 try { 141 parser = context.getResources().getAnimation(id); 142 return createLayoutAnimationFromXml(context, parser); 143 } catch (XmlPullParserException ex) { 144 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 145 Integer.toHexString(id)); 146 rnf.initCause(ex); 147 throw rnf; 148 } catch (IOException ex) { 149 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 150 Integer.toHexString(id)); 151 rnf.initCause(ex); 152 throw rnf; 153 } finally { 154 if (parser != null) parser.close(); 155 } 156 } 157 158 private static LayoutAnimationController createLayoutAnimationFromXml(Context c, 159 XmlPullParser parser) throws XmlPullParserException, IOException { 160 161 return createLayoutAnimationFromXml(c, parser, Xml.asAttributeSet(parser)); 162 } 163 164 private static LayoutAnimationController createLayoutAnimationFromXml(Context c, 165 XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { 166 167 LayoutAnimationController controller = null; 168 169 int type; 170 int depth = parser.getDepth(); 171 172 while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 173 && type != XmlPullParser.END_DOCUMENT) { 174 175 if (type != XmlPullParser.START_TAG) { 176 continue; 177 } 178 179 String name = parser.getName(); 180 181 if ("layoutAnimation".equals(name)) { 182 controller = new LayoutAnimationController(c, attrs); 183 } else if ("gridLayoutAnimation".equals(name)) { 184 controller = new GridLayoutAnimationController(c, attrs); 185 } else { 186 throw new RuntimeException("Unknown layout animation name: " + name); 187 } 188 } 189 190 return controller; 191 } 192 193 /** 194 * Make an animation for objects becoming visible. Uses a slide and fade 195 * effect. 196 * 197 * @param c Context for loading resources 198 * @param fromLeft is the object to be animated coming from the left 199 * @return The new animation 200 */ 201 public static Animation makeInAnimation(Context c, boolean fromLeft) { 202 Animation a; 203 if (fromLeft) { 204 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_left); 205 } else { 206 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_right); 207 } 208 209 a.setInterpolator(new DecelerateInterpolator()); 210 a.setStartTime(currentAnimationTimeMillis()); 211 return a; 212 } 213 214 /** 215 * Make an animation for objects becoming invisible. Uses a slide and fade 216 * effect. 217 * 218 * @param c Context for loading resources 219 * @param toRight is the object to be animated exiting to the right 220 * @return The new animation 221 */ 222 public static Animation makeOutAnimation(Context c, boolean toRight) { 223 Animation a; 224 if (toRight) { 225 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_right); 226 } else { 227 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_left); 228 } 229 230 a.setInterpolator(new AccelerateInterpolator()); 231 a.setStartTime(currentAnimationTimeMillis()); 232 return a; 233 } 234 235 236 /** 237 * Make an animation for objects becoming visible. Uses a slide up and fade 238 * effect. 239 * 240 * @param c Context for loading resources 241 * @return The new animation 242 */ 243 public static Animation makeInChildBottomAnimation(Context c) { 244 Animation a; 245 a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_child_bottom); 246 a.setInterpolator(new AccelerateInterpolator()); 247 a.setStartTime(currentAnimationTimeMillis()); 248 return a; 249 } 250 251 /** 252 * Loads an {@link Interpolator} object from a resource 253 * 254 * @param context Application context used to access resources 255 * @param id The resource id of the animation to load 256 * @return The animation object reference by the specified id 257 * @throws NotFoundException 258 */ 259 public static Interpolator loadInterpolator(Context context, int id) throws NotFoundException { 260 XmlResourceParser parser = null; 261 try { 262 parser = context.getResources().getAnimation(id); 263 return createInterpolatorFromXml(context, parser); 264 } catch (XmlPullParserException ex) { 265 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 266 Integer.toHexString(id)); 267 rnf.initCause(ex); 268 throw rnf; 269 } catch (IOException ex) { 270 NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + 271 Integer.toHexString(id)); 272 rnf.initCause(ex); 273 throw rnf; 274 } finally { 275 if (parser != null) parser.close(); 276 } 277 278 } 279 280 private static Interpolator createInterpolatorFromXml(Context c, XmlPullParser parser) 281 throws XmlPullParserException, IOException { 282 283 Interpolator interpolator = null; 284 285 // Make sure we are on a start tag. 286 int type; 287 int depth = parser.getDepth(); 288 289 while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 290 && type != XmlPullParser.END_DOCUMENT) { 291 292 if (type != XmlPullParser.START_TAG) { 293 continue; 294 } 295 296 AttributeSet attrs = Xml.asAttributeSet(parser); 297 298 String name = parser.getName(); 299 300 301 if (name.equals("linearInterpolator")) { 302 interpolator = new LinearInterpolator(c, attrs); 303 } else if (name.equals("accelerateInterpolator")) { 304 interpolator = new AccelerateInterpolator(c, attrs); 305 } else if (name.equals("decelerateInterpolator")) { 306 interpolator = new DecelerateInterpolator(c, attrs); 307 } else if (name.equals("accelerateDecelerateInterpolator")) { 308 interpolator = new AccelerateDecelerateInterpolator(c, attrs); 309 } else if (name.equals("cycleInterpolator")) { 310 interpolator = new CycleInterpolator(c, attrs); 311 } else if (name.equals("anticipateInterpolator")) { 312 interpolator = new AnticipateInterpolator(c, attrs); 313 } else if (name.equals("overshootInterpolator")) { 314 interpolator = new OvershootInterpolator(c, attrs); 315 } else if (name.equals("anticipateOvershootInterpolator")) { 316 interpolator = new AnticipateOvershootInterpolator(c, attrs); 317 } else if (name.equals("bounceInterpolator")) { 318 interpolator = new BounceInterpolator(c, attrs); 319 } else { 320 throw new RuntimeException("Unknown interpolator name: " + parser.getName()); 321 } 322 323 } 324 325 return interpolator; 326 327 } 328} 329