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 mColumnDelay = d.value; 121 d = Animation.Description.parseValue( 122 a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_rowDelay)); 123 mRowDelay = d.value; 124 //noinspection PointlessBitwiseExpression 125 mDirection = a.getInt(com.android.internal.R.styleable.GridLayoutAnimation_direction, 126 DIRECTION_LEFT_TO_RIGHT | DIRECTION_TOP_TO_BOTTOM); 127 mDirectionPriority = a.getInt(com.android.internal.R.styleable.GridLayoutAnimation_directionPriority, 128 PRIORITY_NONE); 129 130 a.recycle(); 131 } 132 133 /** 134 * Creates a new layout animation controller with a delay of 50% 135 * for both rows and columns and the specified animation. 136 * 137 * @param animation the animation to use on each child of the view group 138 */ GridLayoutAnimationController(Animation animation)139 public GridLayoutAnimationController(Animation animation) { 140 this(animation, 0.5f, 0.5f); 141 } 142 143 /** 144 * Creates a new layout animation controller with the specified delays 145 * and the specified animation. 146 * 147 * @param animation the animation to use on each child of the view group 148 * @param columnDelay the delay by which each column animation must be offset 149 * @param rowDelay the delay by which each row animation must be offset 150 */ GridLayoutAnimationController(Animation animation, float columnDelay, float rowDelay)151 public GridLayoutAnimationController(Animation animation, float columnDelay, float rowDelay) { 152 super(animation); 153 mColumnDelay = columnDelay; 154 mRowDelay = rowDelay; 155 } 156 157 /** 158 * Returns the delay by which the children's animation are offset from one 159 * column to the other. The delay is expressed as a fraction of the 160 * animation duration. 161 * 162 * @return a fraction of the animation duration 163 * 164 * @see #setColumnDelay(float) 165 * @see #getRowDelay() 166 * @see #setRowDelay(float) 167 */ getColumnDelay()168 public float getColumnDelay() { 169 return mColumnDelay; 170 } 171 172 /** 173 * Sets the delay, as a fraction of the animation duration, by which the 174 * children's animations are offset from one column to the other. 175 * 176 * @param columnDelay a fraction of the animation duration 177 * 178 * @see #getColumnDelay() 179 * @see #getRowDelay() 180 * @see #setRowDelay(float) 181 */ setColumnDelay(float columnDelay)182 public void setColumnDelay(float columnDelay) { 183 mColumnDelay = columnDelay; 184 } 185 186 /** 187 * Returns the delay by which the children's animation are offset from one 188 * row to the other. The delay is expressed as a fraction of the 189 * animation duration. 190 * 191 * @return a fraction of the animation duration 192 * 193 * @see #setRowDelay(float) 194 * @see #getColumnDelay() 195 * @see #setColumnDelay(float) 196 */ getRowDelay()197 public float getRowDelay() { 198 return mRowDelay; 199 } 200 201 /** 202 * Sets the delay, as a fraction of the animation duration, by which the 203 * children's animations are offset from one row to the other. 204 * 205 * @param rowDelay a fraction of the animation duration 206 * 207 * @see #getRowDelay() 208 * @see #getColumnDelay() 209 * @see #setColumnDelay(float) 210 */ setRowDelay(float rowDelay)211 public void setRowDelay(float rowDelay) { 212 mRowDelay = rowDelay; 213 } 214 215 /** 216 * Returns the direction of the animation. {@link #DIRECTION_HORIZONTAL_MASK} 217 * and {@link #DIRECTION_VERTICAL_MASK} can be used to retrieve the 218 * horizontal and vertical components of the direction. 219 * 220 * @return the direction of the animation 221 * 222 * @see #setDirection(int) 223 * @see #DIRECTION_BOTTOM_TO_TOP 224 * @see #DIRECTION_TOP_TO_BOTTOM 225 * @see #DIRECTION_LEFT_TO_RIGHT 226 * @see #DIRECTION_RIGHT_TO_LEFT 227 * @see #DIRECTION_HORIZONTAL_MASK 228 * @see #DIRECTION_VERTICAL_MASK 229 */ getDirection()230 public int getDirection() { 231 return mDirection; 232 } 233 234 /** 235 * Sets the direction of the animation. The direction is expressed as an 236 * integer containing a horizontal and vertical component. For instance, 237 * <code>DIRECTION_BOTTOM_TO_TOP | DIRECTION_RIGHT_TO_LEFT</code>. 238 * 239 * @param direction the direction of the animation 240 * 241 * @see #getDirection() 242 * @see #DIRECTION_BOTTOM_TO_TOP 243 * @see #DIRECTION_TOP_TO_BOTTOM 244 * @see #DIRECTION_LEFT_TO_RIGHT 245 * @see #DIRECTION_RIGHT_TO_LEFT 246 * @see #DIRECTION_HORIZONTAL_MASK 247 * @see #DIRECTION_VERTICAL_MASK 248 */ setDirection(int direction)249 public void setDirection(int direction) { 250 mDirection = direction; 251 } 252 253 /** 254 * Returns the direction priority for the animation. The priority can 255 * be either {@link #PRIORITY_NONE}, {@link #PRIORITY_COLUMN} or 256 * {@link #PRIORITY_ROW}. 257 * 258 * @return the priority of the animation direction 259 * 260 * @see #setDirectionPriority(int) 261 * @see #PRIORITY_COLUMN 262 * @see #PRIORITY_NONE 263 * @see #PRIORITY_ROW 264 */ getDirectionPriority()265 public int getDirectionPriority() { 266 return mDirectionPriority; 267 } 268 269 /** 270 * Specifies the direction priority of the animation. For instance, 271 * {@link #PRIORITY_COLUMN} will give priority to columns: the animation 272 * will first play on the column, then on the rows.Z 273 * 274 * @param directionPriority the direction priority of the animation 275 * 276 * @see #getDirectionPriority() 277 * @see #PRIORITY_COLUMN 278 * @see #PRIORITY_NONE 279 * @see #PRIORITY_ROW 280 */ setDirectionPriority(int directionPriority)281 public void setDirectionPriority(int directionPriority) { 282 mDirectionPriority = directionPriority; 283 } 284 285 /** 286 * {@inheritDoc} 287 */ 288 @Override willOverlap()289 public boolean willOverlap() { 290 return mColumnDelay < 1.0f || mRowDelay < 1.0f; 291 } 292 293 /** 294 * {@inheritDoc} 295 */ 296 @Override getDelayForView(View view)297 protected long getDelayForView(View view) { 298 ViewGroup.LayoutParams lp = view.getLayoutParams(); 299 AnimationParameters params = (AnimationParameters) lp.layoutAnimationParameters; 300 301 if (params == null) { 302 return 0; 303 } 304 305 final int column = getTransformedColumnIndex(params); 306 final int row = getTransformedRowIndex(params); 307 308 final int rowsCount = params.rowsCount; 309 final int columnsCount = params.columnsCount; 310 311 final long duration = mAnimation.getDuration(); 312 final float columnDelay = mColumnDelay * duration; 313 final float rowDelay = mRowDelay * duration; 314 315 float totalDelay; 316 long viewDelay; 317 318 if (mInterpolator == null) { 319 mInterpolator = new LinearInterpolator(); 320 } 321 322 switch (mDirectionPriority) { 323 case PRIORITY_COLUMN: 324 viewDelay = (long) (row * rowDelay + column * rowsCount * rowDelay); 325 totalDelay = rowsCount * rowDelay + columnsCount * rowsCount * rowDelay; 326 break; 327 case PRIORITY_ROW: 328 viewDelay = (long) (column * columnDelay + row * columnsCount * columnDelay); 329 totalDelay = columnsCount * columnDelay + rowsCount * columnsCount * columnDelay; 330 break; 331 case PRIORITY_NONE: 332 default: 333 viewDelay = (long) (column * columnDelay + row * rowDelay); 334 totalDelay = columnsCount * columnDelay + rowsCount * rowDelay; 335 break; 336 } 337 338 float normalizedDelay = viewDelay / totalDelay; 339 normalizedDelay = mInterpolator.getInterpolation(normalizedDelay); 340 341 return (long) (normalizedDelay * totalDelay); 342 } 343 getTransformedColumnIndex(AnimationParameters params)344 private int getTransformedColumnIndex(AnimationParameters params) { 345 int index; 346 switch (getOrder()) { 347 case ORDER_REVERSE: 348 index = params.columnsCount - 1 - params.column; 349 break; 350 case ORDER_RANDOM: 351 if (mRandomizer == null) { 352 mRandomizer = new Random(); 353 } 354 index = (int) (params.columnsCount * mRandomizer.nextFloat()); 355 break; 356 case ORDER_NORMAL: 357 default: 358 index = params.column; 359 break; 360 } 361 362 int direction = mDirection & DIRECTION_HORIZONTAL_MASK; 363 if (direction == DIRECTION_RIGHT_TO_LEFT) { 364 index = params.columnsCount - 1 - index; 365 } 366 367 return index; 368 } 369 getTransformedRowIndex(AnimationParameters params)370 private int getTransformedRowIndex(AnimationParameters params) { 371 int index; 372 switch (getOrder()) { 373 case ORDER_REVERSE: 374 index = params.rowsCount - 1 - params.row; 375 break; 376 case ORDER_RANDOM: 377 if (mRandomizer == null) { 378 mRandomizer = new Random(); 379 } 380 index = (int) (params.rowsCount * mRandomizer.nextFloat()); 381 break; 382 case ORDER_NORMAL: 383 default: 384 index = params.row; 385 break; 386 } 387 388 int direction = mDirection & DIRECTION_VERTICAL_MASK; 389 if (direction == DIRECTION_BOTTOM_TO_TOP) { 390 index = params.rowsCount - 1 - index; 391 } 392 393 return index; 394 } 395 396 /** 397 * The set of parameters that has to be attached to each view contained in 398 * the view group animated by the grid layout animation controller. These 399 * parameters are used to compute the start time of each individual view's 400 * animation. 401 */ 402 public static class AnimationParameters extends 403 LayoutAnimationController.AnimationParameters { 404 /** 405 * The view group's column to which the view belongs. 406 */ 407 public int column; 408 409 /** 410 * The view group's row to which the view belongs. 411 */ 412 public int row; 413 414 /** 415 * The number of columns in the view's enclosing grid layout. 416 */ 417 public int columnsCount; 418 419 /** 420 * The number of rows in the view's enclosing grid layout. 421 */ 422 public int rowsCount; 423 } 424 } 425