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 17 package android.view.animation; 18 19 import android.content.Context; 20 import android.content.res.TypedArray; 21 import android.util.AttributeSet; 22 import android.view.View; 23 import android.view.ViewGroup; 24 25 import java.util.Random; 26 27 /** 28 * A layout animation controller is used to animated a grid layout's children. 29 * 30 * While {@link LayoutAnimationController} relies only on the index of the child 31 * in the view group to compute the animation delay, this class uses both the 32 * X and Y coordinates of the child within a grid. 33 * 34 * In addition, the animation direction can be controlled. The default direction 35 * is <code>DIRECTION_LEFT_TO_RIGHT | DIRECTION_TOP_TO_BOTTOM</code>. You can 36 * also set the animation priority to columns or rows. The default priority is 37 * none. 38 * 39 * Information used to compute the animation delay of each child are stored 40 * in an instance of 41 * {@link android.view.animation.GridLayoutAnimationController.AnimationParameters}, 42 * itself stored in the {@link android.view.ViewGroup.LayoutParams} of the view. 43 * 44 * @see LayoutAnimationController 45 * @see android.widget.GridView 46 * 47 * @attr ref android.R.styleable#GridLayoutAnimation_columnDelay 48 * @attr ref android.R.styleable#GridLayoutAnimation_rowDelay 49 * @attr ref android.R.styleable#GridLayoutAnimation_direction 50 * @attr ref android.R.styleable#GridLayoutAnimation_directionPriority 51 */ 52 public class GridLayoutAnimationController extends LayoutAnimationController { 53 /** 54 * Animates the children starting from the left of the grid to the right. 55 */ 56 public static final int DIRECTION_LEFT_TO_RIGHT = 0x0; 57 58 /** 59 * Animates the children starting from the right of the grid to the left. 60 */ 61 public static final int DIRECTION_RIGHT_TO_LEFT = 0x1; 62 63 /** 64 * Animates the children starting from the top of the grid to the bottom. 65 */ 66 public static final int DIRECTION_TOP_TO_BOTTOM = 0x0; 67 68 /** 69 * Animates the children starting from the bottom of the grid to the top. 70 */ 71 public static final int DIRECTION_BOTTOM_TO_TOP = 0x2; 72 73 /** 74 * Bitmask used to retrieve the horizontal component of the direction. 75 */ 76 public static final int DIRECTION_HORIZONTAL_MASK = 0x1; 77 78 /** 79 * Bitmask used to retrieve the vertical component of the direction. 80 */ 81 public static final int DIRECTION_VERTICAL_MASK = 0x2; 82 83 /** 84 * Rows and columns are animated at the same time. 85 */ 86 public static final int PRIORITY_NONE = 0; 87 88 /** 89 * Columns are animated first. 90 */ 91 public static final int PRIORITY_COLUMN = 1; 92 93 /** 94 * Rows are animated first. 95 */ 96 public static final int PRIORITY_ROW = 2; 97 98 private float mColumnDelay; 99 private float mRowDelay; 100 101 private int mDirection; 102 private int mDirectionPriority; 103 104 /** 105 * Creates a new grid layout animation controller from external resources. 106 * 107 * @param context the Context the view group is running in, through which 108 * it can access the resources 109 * @param attrs the attributes of the XML tag that is inflating the 110 * layout animation controller 111 */ GridLayoutAnimationController(Context context, AttributeSet attrs)112 public GridLayoutAnimationController(Context context, AttributeSet attrs) { 113 super(context, attrs); 114 115 TypedArray a = context.obtainStyledAttributes(attrs, 116 com.android.internal.R.styleable.GridLayoutAnimation); 117 118 Animation.Description d = Animation.Description.parseValue( 119 a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_columnDelay), 120 context); 121 mColumnDelay = d.value; 122 d = Animation.Description.parseValue( 123 a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_rowDelay), 124 context); 125 mRowDelay = d.value; 126 //noinspection PointlessBitwiseExpression 127 mDirection = a.getInt(com.android.internal.R.styleable.GridLayoutAnimation_direction, 128 DIRECTION_LEFT_TO_RIGHT | DIRECTION_TOP_TO_BOTTOM); 129 mDirectionPriority = a.getInt(com.android.internal.R.styleable.GridLayoutAnimation_directionPriority, 130 PRIORITY_NONE); 131 132 a.recycle(); 133 } 134 135 /** 136 * Creates a new layout animation controller with a delay of 50% 137 * for both rows and columns and the specified animation. 138 * 139 * @param animation the animation to use on each child of the view group 140 */ GridLayoutAnimationController(Animation animation)141 public GridLayoutAnimationController(Animation animation) { 142 this(animation, 0.5f, 0.5f); 143 } 144 145 /** 146 * Creates a new layout animation controller with the specified delays 147 * and the specified animation. 148 * 149 * @param animation the animation to use on each child of the view group 150 * @param columnDelay the delay by which each column animation must be offset 151 * @param rowDelay the delay by which each row animation must be offset 152 */ GridLayoutAnimationController(Animation animation, float columnDelay, float rowDelay)153 public GridLayoutAnimationController(Animation animation, float columnDelay, float rowDelay) { 154 super(animation); 155 mColumnDelay = columnDelay; 156 mRowDelay = rowDelay; 157 } 158 159 /** 160 * Returns the delay by which the children's animation are offset from one 161 * column to the other. The delay is expressed as a fraction of the 162 * animation duration. 163 * 164 * @return a fraction of the animation duration 165 * 166 * @see #setColumnDelay(float) 167 * @see #getRowDelay() 168 * @see #setRowDelay(float) 169 */ getColumnDelay()170 public float getColumnDelay() { 171 return mColumnDelay; 172 } 173 174 /** 175 * Sets the delay, as a fraction of the animation duration, by which the 176 * children's animations are offset from one column to the other. 177 * 178 * @param columnDelay a fraction of the animation duration 179 * 180 * @see #getColumnDelay() 181 * @see #getRowDelay() 182 * @see #setRowDelay(float) 183 */ setColumnDelay(float columnDelay)184 public void setColumnDelay(float columnDelay) { 185 mColumnDelay = columnDelay; 186 } 187 188 /** 189 * Returns the delay by which the children's animation are offset from one 190 * row to the other. The delay is expressed as a fraction of the 191 * animation duration. 192 * 193 * @return a fraction of the animation duration 194 * 195 * @see #setRowDelay(float) 196 * @see #getColumnDelay() 197 * @see #setColumnDelay(float) 198 */ getRowDelay()199 public float getRowDelay() { 200 return mRowDelay; 201 } 202 203 /** 204 * Sets the delay, as a fraction of the animation duration, by which the 205 * children's animations are offset from one row to the other. 206 * 207 * @param rowDelay a fraction of the animation duration 208 * 209 * @see #getRowDelay() 210 * @see #getColumnDelay() 211 * @see #setColumnDelay(float) 212 */ setRowDelay(float rowDelay)213 public void setRowDelay(float rowDelay) { 214 mRowDelay = rowDelay; 215 } 216 217 /** 218 * Returns the direction of the animation. {@link #DIRECTION_HORIZONTAL_MASK} 219 * and {@link #DIRECTION_VERTICAL_MASK} can be used to retrieve the 220 * horizontal and vertical components of the direction. 221 * 222 * @return the direction of the animation 223 * 224 * @see #setDirection(int) 225 * @see #DIRECTION_BOTTOM_TO_TOP 226 * @see #DIRECTION_TOP_TO_BOTTOM 227 * @see #DIRECTION_LEFT_TO_RIGHT 228 * @see #DIRECTION_RIGHT_TO_LEFT 229 * @see #DIRECTION_HORIZONTAL_MASK 230 * @see #DIRECTION_VERTICAL_MASK 231 */ getDirection()232 public int getDirection() { 233 return mDirection; 234 } 235 236 /** 237 * Sets the direction of the animation. The direction is expressed as an 238 * integer containing a horizontal and vertical component. For instance, 239 * <code>DIRECTION_BOTTOM_TO_TOP | DIRECTION_RIGHT_TO_LEFT</code>. 240 * 241 * @param direction the direction of the animation 242 * 243 * @see #getDirection() 244 * @see #DIRECTION_BOTTOM_TO_TOP 245 * @see #DIRECTION_TOP_TO_BOTTOM 246 * @see #DIRECTION_LEFT_TO_RIGHT 247 * @see #DIRECTION_RIGHT_TO_LEFT 248 * @see #DIRECTION_HORIZONTAL_MASK 249 * @see #DIRECTION_VERTICAL_MASK 250 */ setDirection(int direction)251 public void setDirection(int direction) { 252 mDirection = direction; 253 } 254 255 /** 256 * Returns the direction priority for the animation. The priority can 257 * be either {@link #PRIORITY_NONE}, {@link #PRIORITY_COLUMN} or 258 * {@link #PRIORITY_ROW}. 259 * 260 * @return the priority of the animation direction 261 * 262 * @see #setDirectionPriority(int) 263 * @see #PRIORITY_COLUMN 264 * @see #PRIORITY_NONE 265 * @see #PRIORITY_ROW 266 */ getDirectionPriority()267 public int getDirectionPriority() { 268 return mDirectionPriority; 269 } 270 271 /** 272 * Specifies the direction priority of the animation. For instance, 273 * {@link #PRIORITY_COLUMN} will give priority to columns: the animation 274 * will first play on the column, then on the rows.Z 275 * 276 * @param directionPriority the direction priority of the animation 277 * 278 * @see #getDirectionPriority() 279 * @see #PRIORITY_COLUMN 280 * @see #PRIORITY_NONE 281 * @see #PRIORITY_ROW 282 */ setDirectionPriority(int directionPriority)283 public void setDirectionPriority(int directionPriority) { 284 mDirectionPriority = directionPriority; 285 } 286 287 /** 288 * {@inheritDoc} 289 */ 290 @Override willOverlap()291 public boolean willOverlap() { 292 return mColumnDelay < 1.0f || mRowDelay < 1.0f; 293 } 294 295 /** 296 * {@inheritDoc} 297 */ 298 @Override getDelayForView(View view)299 protected long getDelayForView(View view) { 300 ViewGroup.LayoutParams lp = view.getLayoutParams(); 301 AnimationParameters params = (AnimationParameters) lp.layoutAnimationParameters; 302 303 if (params == null) { 304 return 0; 305 } 306 307 final int column = getTransformedColumnIndex(params); 308 final int row = getTransformedRowIndex(params); 309 310 final int rowsCount = params.rowsCount; 311 final int columnsCount = params.columnsCount; 312 313 final long duration = mAnimation.getDuration(); 314 final float columnDelay = mColumnDelay * duration; 315 final float rowDelay = mRowDelay * duration; 316 317 float totalDelay; 318 long viewDelay; 319 320 if (mInterpolator == null) { 321 mInterpolator = new LinearInterpolator(); 322 } 323 324 switch (mDirectionPriority) { 325 case PRIORITY_COLUMN: 326 viewDelay = (long) (row * rowDelay + column * rowsCount * rowDelay); 327 totalDelay = rowsCount * rowDelay + columnsCount * rowsCount * rowDelay; 328 break; 329 case PRIORITY_ROW: 330 viewDelay = (long) (column * columnDelay + row * columnsCount * columnDelay); 331 totalDelay = columnsCount * columnDelay + rowsCount * columnsCount * columnDelay; 332 break; 333 case PRIORITY_NONE: 334 default: 335 viewDelay = (long) (column * columnDelay + row * rowDelay); 336 totalDelay = columnsCount * columnDelay + rowsCount * rowDelay; 337 break; 338 } 339 340 float normalizedDelay = viewDelay / totalDelay; 341 normalizedDelay = mInterpolator.getInterpolation(normalizedDelay); 342 343 return (long) (normalizedDelay * totalDelay); 344 } 345 getTransformedColumnIndex(AnimationParameters params)346 private int getTransformedColumnIndex(AnimationParameters params) { 347 int index; 348 switch (getOrder()) { 349 case ORDER_REVERSE: 350 index = params.columnsCount - 1 - params.column; 351 break; 352 case ORDER_RANDOM: 353 if (mRandomizer == null) { 354 mRandomizer = new Random(); 355 } 356 index = (int) (params.columnsCount * mRandomizer.nextFloat()); 357 break; 358 case ORDER_NORMAL: 359 default: 360 index = params.column; 361 break; 362 } 363 364 int direction = mDirection & DIRECTION_HORIZONTAL_MASK; 365 if (direction == DIRECTION_RIGHT_TO_LEFT) { 366 index = params.columnsCount - 1 - index; 367 } 368 369 return index; 370 } 371 getTransformedRowIndex(AnimationParameters params)372 private int getTransformedRowIndex(AnimationParameters params) { 373 int index; 374 switch (getOrder()) { 375 case ORDER_REVERSE: 376 index = params.rowsCount - 1 - params.row; 377 break; 378 case ORDER_RANDOM: 379 if (mRandomizer == null) { 380 mRandomizer = new Random(); 381 } 382 index = (int) (params.rowsCount * mRandomizer.nextFloat()); 383 break; 384 case ORDER_NORMAL: 385 default: 386 index = params.row; 387 break; 388 } 389 390 int direction = mDirection & DIRECTION_VERTICAL_MASK; 391 if (direction == DIRECTION_BOTTOM_TO_TOP) { 392 index = params.rowsCount - 1 - index; 393 } 394 395 return index; 396 } 397 398 /** 399 * The set of parameters that has to be attached to each view contained in 400 * the view group animated by the grid layout animation controller. These 401 * parameters are used to compute the start time of each individual view's 402 * animation. 403 */ 404 public static class AnimationParameters extends 405 LayoutAnimationController.AnimationParameters { 406 /** 407 * The view group's column to which the view belongs. 408 */ 409 public int column; 410 411 /** 412 * The view group's row to which the view belongs. 413 */ 414 public int row; 415 416 /** 417 * The number of columns in the view's enclosing grid layout. 418 */ 419 public int columnsCount; 420 421 /** 422 * The number of rows in the view's enclosing grid layout. 423 */ 424 public int rowsCount; 425 } 426 } 427