1 /* <lambda>null2 * Copyright 2020 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 androidx.compose.foundation.layout 18 19 import androidx.compose.foundation.layout.internal.JvmDefaultWithCompatibility 20 import androidx.compose.runtime.Immutable 21 import androidx.compose.runtime.Stable 22 import androidx.compose.ui.Alignment 23 import androidx.compose.ui.unit.Density 24 import androidx.compose.ui.unit.Dp 25 import androidx.compose.ui.unit.LayoutDirection 26 import androidx.compose.ui.unit.dp 27 import androidx.compose.ui.util.fastRoundToInt 28 import kotlin.math.min 29 30 /** 31 * Used to specify the arrangement of the layout's children in layouts like [Row] or [Column] in the 32 * main axis direction (horizontal and vertical, respectively). 33 * 34 * Below is an illustration of different horizontal arrangements in [Row]s:  36 * 37 * Different vertical arrangements in [Column]s:  39 */ 40 @Immutable 41 object Arrangement { 42 /** 43 * Used to specify the horizontal arrangement of the layout's children in layouts like [Row]. 44 */ 45 @Stable 46 @JvmDefaultWithCompatibility 47 interface Horizontal { 48 /** Spacing that should be added between any two adjacent layout children. */ 49 val spacing 50 get() = 0.dp 51 52 /** 53 * Horizontally places the layout children. 54 * 55 * @param totalSize Available space that can be occupied by the children, in pixels. 56 * @param sizes An array of sizes of all children, in pixels. 57 * @param layoutDirection A layout direction, left-to-right or right-to-left, of the parent 58 * layout that should be taken into account when determining positions of the children. 59 * @param outPositions An array of the size of [sizes] that returns the calculated positions 60 * relative to the left, in pixels. 61 */ 62 fun Density.arrange( 63 totalSize: Int, 64 sizes: IntArray, 65 layoutDirection: LayoutDirection, 66 outPositions: IntArray 67 ) 68 } 69 70 /** 71 * Used to specify the vertical arrangement of the layout's children in layouts like [Column]. 72 */ 73 @Stable 74 @JvmDefaultWithCompatibility 75 interface Vertical { 76 /** Spacing that should be added between any two adjacent layout children. */ 77 val spacing 78 get() = 0.dp 79 80 /** 81 * Vertically places the layout children. 82 * 83 * @param totalSize Available space that can be occupied by the children, in pixels. 84 * @param sizes An array of sizes of all children, in pixels. 85 * @param outPositions An array of the size of [sizes] that returns the calculated positions 86 * relative to the top, in pixels. 87 */ 88 fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) 89 } 90 91 /** 92 * Used to specify the horizontal arrangement of the layout's children in horizontal layouts 93 * like [Row], or the vertical arrangement of the layout's children in vertical layouts like 94 * [Column]. 95 */ 96 @Stable 97 @JvmDefaultWithCompatibility 98 interface HorizontalOrVertical : Horizontal, Vertical { 99 /** Spacing that should be added between any two adjacent layout children. */ 100 override val spacing: Dp 101 get() = 0.dp 102 } 103 104 /** 105 * Place children horizontally such that they are as close as possible to the beginning of the 106 * horizontal axis (left if the layout direction is LTR, right otherwise). Visually: 123#### for 107 * LTR and ####321. 108 */ 109 @Stable 110 val Start = 111 object : Horizontal { 112 override fun Density.arrange( 113 totalSize: Int, 114 sizes: IntArray, 115 layoutDirection: LayoutDirection, 116 outPositions: IntArray 117 ) = 118 if (layoutDirection == LayoutDirection.Ltr) { 119 placeLeftOrTop(sizes, outPositions, reverseInput = false) 120 } else { 121 placeRightOrBottom(totalSize, sizes, outPositions, reverseInput = true) 122 } 123 124 override fun toString() = "Arrangement#Start" 125 } 126 127 /** 128 * Place children horizontally such that they are as close as possible to the end of the main 129 * axis. Visually: ####123 for LTR and 321#### for RTL. 130 */ 131 @Stable 132 val End = 133 object : Horizontal { 134 override fun Density.arrange( 135 totalSize: Int, 136 sizes: IntArray, 137 layoutDirection: LayoutDirection, 138 outPositions: IntArray 139 ) = 140 if (layoutDirection == LayoutDirection.Ltr) { 141 placeRightOrBottom(totalSize, sizes, outPositions, reverseInput = false) 142 } else { 143 placeLeftOrTop(sizes, outPositions, reverseInput = true) 144 } 145 146 override fun toString() = "Arrangement#End" 147 } 148 149 /** 150 * Place children vertically such that they are as close as possible to the top of the main 151 * axis. Visually: (top) 123#### (bottom) 152 */ 153 @Stable 154 val Top = 155 object : Vertical { 156 override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) = 157 placeLeftOrTop(sizes, outPositions, reverseInput = false) 158 159 override fun toString() = "Arrangement#Top" 160 } 161 162 /** 163 * Place children vertically such that they are as close as possible to the bottom of the main 164 * axis. Visually: (top) ####123 (bottom) 165 */ 166 @Stable 167 val Bottom = 168 object : Vertical { 169 override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) = 170 placeRightOrBottom(totalSize, sizes, outPositions, reverseInput = false) 171 172 override fun toString() = "Arrangement#Bottom" 173 } 174 175 /** 176 * Place children such that they are as close as possible to the middle of the main axis. 177 * Visually: ##123## for LTR and ##321## for RTL. 178 */ 179 @Stable 180 val Center = 181 object : HorizontalOrVertical { 182 override val spacing = 0.dp 183 184 override fun Density.arrange( 185 totalSize: Int, 186 sizes: IntArray, 187 layoutDirection: LayoutDirection, 188 outPositions: IntArray 189 ) = 190 if (layoutDirection == LayoutDirection.Ltr) { 191 placeCenter(totalSize, sizes, outPositions, reverseInput = false) 192 } else { 193 placeCenter(totalSize, sizes, outPositions, reverseInput = true) 194 } 195 196 override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) = 197 placeCenter(totalSize, sizes, outPositions, reverseInput = false) 198 199 override fun toString() = "Arrangement#Center" 200 } 201 202 /** 203 * Place children such that they are spaced evenly across the main axis, including free space 204 * before the first child and after the last child. Visually: #1#2#3# for LTR and #3#2#1# for 205 * RTL. 206 */ 207 @Stable 208 val SpaceEvenly = 209 object : HorizontalOrVertical { 210 override val spacing = 0.dp 211 212 override fun Density.arrange( 213 totalSize: Int, 214 sizes: IntArray, 215 layoutDirection: LayoutDirection, 216 outPositions: IntArray 217 ) = 218 if (layoutDirection == LayoutDirection.Ltr) { 219 placeSpaceEvenly(totalSize, sizes, outPositions, reverseInput = false) 220 } else { 221 placeSpaceEvenly(totalSize, sizes, outPositions, reverseInput = true) 222 } 223 224 override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) = 225 placeSpaceEvenly(totalSize, sizes, outPositions, reverseInput = false) 226 227 override fun toString() = "Arrangement#SpaceEvenly" 228 } 229 230 /** 231 * Place children such that they are spaced evenly across the main axis, without free space 232 * before the first child or after the last child. Visually: 1##2##3 for LTR or 3##2##1 for RTL. 233 */ 234 @Stable 235 val SpaceBetween = 236 object : HorizontalOrVertical { 237 override val spacing = 0.dp 238 239 override fun Density.arrange( 240 totalSize: Int, 241 sizes: IntArray, 242 layoutDirection: LayoutDirection, 243 outPositions: IntArray 244 ) = 245 if (layoutDirection == LayoutDirection.Ltr) { 246 placeSpaceBetween(totalSize, sizes, outPositions, reverseInput = false) 247 } else { 248 placeSpaceBetween(totalSize, sizes, outPositions, reverseInput = true) 249 } 250 251 override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) = 252 placeSpaceBetween(totalSize, sizes, outPositions, reverseInput = false) 253 254 override fun toString() = "Arrangement#SpaceBetween" 255 } 256 257 /** 258 * Place children such that they are spaced evenly across the main axis, including free space 259 * before the first child and after the last child, but half the amount of space existing 260 * otherwise between two consecutive children. Visually: #1##2##3# for LTR and #3##2##1# for RTL 261 */ 262 @Stable 263 val SpaceAround = 264 object : HorizontalOrVertical { 265 override val spacing = 0.dp 266 267 override fun Density.arrange( 268 totalSize: Int, 269 sizes: IntArray, 270 layoutDirection: LayoutDirection, 271 outPositions: IntArray 272 ) = 273 if (layoutDirection == LayoutDirection.Ltr) { 274 placeSpaceAround(totalSize, sizes, outPositions, reverseInput = false) 275 } else { 276 placeSpaceAround(totalSize, sizes, outPositions, reverseInput = true) 277 } 278 279 override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) = 280 placeSpaceAround(totalSize, sizes, outPositions, reverseInput = false) 281 282 override fun toString() = "Arrangement#SpaceAround" 283 } 284 285 /** 286 * Place children such that each two adjacent ones are spaced by a fixed [space] distance across 287 * the main axis. The spacing will be subtracted from the available space that the children can 288 * occupy. The [space] can be negative, in which case children will overlap. 289 * 290 * To change alignment of the spaced children horizontally or vertically, use [spacedBy] 291 * overloads with `alignment` parameter. 292 * 293 * @param space The space between adjacent children. 294 */ 295 @Stable 296 fun spacedBy(space: Dp): HorizontalOrVertical = 297 SpacedAligned(space, true) { size, layoutDirection -> 298 Alignment.Start.align(0, size, layoutDirection) 299 } 300 301 /** 302 * Place children horizontally such that each two adjacent ones are spaced by a fixed [space] 303 * distance. The spacing will be subtracted from the available width that the children can 304 * occupy. An [alignment] can be specified to align the spaced children horizontally inside the 305 * parent, in case there is empty width remaining. The [space] can be negative, in which case 306 * children will overlap. 307 * 308 * @param space The space between adjacent children. 309 * @param alignment The alignment of the spaced children inside the parent. 310 */ 311 @Stable 312 fun spacedBy(space: Dp, alignment: Alignment.Horizontal): Horizontal = 313 SpacedAligned(space, true) { size, layoutDirection -> 314 alignment.align(0, size, layoutDirection) 315 } 316 317 /** 318 * Place children vertically such that each two adjacent ones are spaced by a fixed [space] 319 * distance. The spacing will be subtracted from the available height that the children can 320 * occupy. An [alignment] can be specified to align the spaced children vertically inside the 321 * parent, in case there is empty height remaining. The [space] can be negative, in which case 322 * children will overlap. 323 * 324 * @param space The space between adjacent children. 325 * @param alignment The alignment of the spaced children inside the parent. 326 */ 327 @Stable 328 fun spacedBy(space: Dp, alignment: Alignment.Vertical): Vertical = 329 SpacedAligned(space, false) { size, _ -> alignment.align(0, size) } 330 331 /** 332 * Place children horizontally one next to the other and align the obtained group according to 333 * an [alignment]. 334 * 335 * @param alignment The alignment of the children inside the parent. 336 */ 337 @Stable 338 fun aligned(alignment: Alignment.Horizontal): Horizontal = 339 SpacedAligned(0.dp, true) { size, layoutDirection -> 340 alignment.align(0, size, layoutDirection) 341 } 342 343 /** 344 * Place children vertically one next to the other and align the obtained group according to an 345 * [alignment]. 346 * 347 * @param alignment The alignment of the children inside the parent. 348 */ 349 @Stable 350 fun aligned(alignment: Alignment.Vertical): Vertical = 351 SpacedAligned(0.dp, false) { size, _ -> alignment.align(0, size) } 352 353 @Immutable 354 object Absolute { 355 /** 356 * Place children horizontally such that they are as close as possible to the left edge of 357 * the [Row]. 358 * 359 * Unlike [Arrangement.Start], when the layout direction is RTL, the children will not be 360 * mirrored and as such children will appear in the order they are composed inside the 361 * [Row]. 362 * 363 * Visually: 123#### 364 */ 365 @Stable 366 val Left = 367 object : Horizontal { 368 override fun Density.arrange( 369 totalSize: Int, 370 sizes: IntArray, 371 layoutDirection: LayoutDirection, 372 outPositions: IntArray 373 ) = placeLeftOrTop(sizes, outPositions, reverseInput = false) 374 375 override fun toString() = "AbsoluteArrangement#Left" 376 } 377 378 /** 379 * Place children such that they are as close as possible to the middle of the [Row]. 380 * 381 * Unlike [Arrangement.Center], when the layout direction is RTL, the children will not be 382 * mirrored and as such children will appear in the order they are composed inside the 383 * [Row]. 384 * 385 * Visually: ##123## 386 */ 387 @Stable 388 val Center = 389 object : Horizontal { 390 override fun Density.arrange( 391 totalSize: Int, 392 sizes: IntArray, 393 layoutDirection: LayoutDirection, 394 outPositions: IntArray 395 ) = placeCenter(totalSize, sizes, outPositions, reverseInput = false) 396 397 override fun toString() = "AbsoluteArrangement#Center" 398 } 399 400 /** 401 * Place children horizontally such that they are as close as possible to the right edge of 402 * the [Row]. 403 * 404 * Unlike [Arrangement.End], when the layout direction is RTL, the children will not be 405 * mirrored and as such children will appear in the order they are composed inside the 406 * [Row]. 407 * 408 * Visually: ####123 409 */ 410 @Stable 411 val Right = 412 object : Horizontal { 413 override fun Density.arrange( 414 totalSize: Int, 415 sizes: IntArray, 416 layoutDirection: LayoutDirection, 417 outPositions: IntArray 418 ) = placeRightOrBottom(totalSize, sizes, outPositions, reverseInput = false) 419 420 override fun toString() = "AbsoluteArrangement#Right" 421 } 422 423 /** 424 * Place children such that they are spaced evenly across the main axis, without free space 425 * before the first child or after the last child. 426 * 427 * Unlike [Arrangement.SpaceBetween], when the layout direction is RTL, the children will 428 * not be mirrored and as such children will appear in the order they are composed inside 429 * the [Row]. 430 * 431 * Visually: 1##2##3 432 */ 433 @Stable 434 val SpaceBetween = 435 object : Horizontal { 436 override fun Density.arrange( 437 totalSize: Int, 438 sizes: IntArray, 439 layoutDirection: LayoutDirection, 440 outPositions: IntArray 441 ) = placeSpaceBetween(totalSize, sizes, outPositions, reverseInput = false) 442 443 override fun toString() = "AbsoluteArrangement#SpaceBetween" 444 } 445 446 /** 447 * Place children such that they are spaced evenly across the main axis, including free 448 * space before the first child and after the last child. 449 * 450 * Unlike [Arrangement.SpaceEvenly], when the layout direction is RTL, the children will not 451 * be mirrored and as such children will appear in the order they are composed inside the 452 * [Row]. 453 * 454 * Visually: #1#2#3# 455 */ 456 @Stable 457 val SpaceEvenly = 458 object : Horizontal { 459 override fun Density.arrange( 460 totalSize: Int, 461 sizes: IntArray, 462 layoutDirection: LayoutDirection, 463 outPositions: IntArray 464 ) = placeSpaceEvenly(totalSize, sizes, outPositions, reverseInput = false) 465 466 override fun toString() = "AbsoluteArrangement#SpaceEvenly" 467 } 468 469 /** 470 * Place children such that they are spaced evenly horizontally, including free space before 471 * the first child and after the last child, but half the amount of space existing otherwise 472 * between two consecutive children. 473 * 474 * Unlike [Arrangement.SpaceAround], when the layout direction is RTL, the children will not 475 * be mirrored and as such children will appear in the order they are composed inside the 476 * [Row]. 477 * 478 * Visually: #1##2##3##4# 479 */ 480 @Stable 481 val SpaceAround = 482 object : Horizontal { 483 override fun Density.arrange( 484 totalSize: Int, 485 sizes: IntArray, 486 layoutDirection: LayoutDirection, 487 outPositions: IntArray 488 ) = placeSpaceAround(totalSize, sizes, outPositions, reverseInput = false) 489 490 override fun toString() = "AbsoluteArrangement#SpaceAround" 491 } 492 493 /** 494 * Place children such that each two adjacent ones are spaced by a fixed [space] distance 495 * across the main axis. The spacing will be subtracted from the available space that the 496 * children can occupy. 497 * 498 * Unlike [Arrangement.spacedBy], when the layout direction is RTL, the children will not be 499 * mirrored and as such children will appear in the order they are composed inside the 500 * [Row]. 501 * 502 * @param space The space between adjacent children. 503 */ 504 @Stable fun spacedBy(space: Dp): HorizontalOrVertical = SpacedAligned(space, false, null) 505 506 /** 507 * Place children horizontally such that each two adjacent ones are spaced by a fixed 508 * [space] distance. The spacing will be subtracted from the available width that the 509 * children can occupy. An [alignment] can be specified to align the spaced children 510 * horizontally inside the parent, in case there is empty width remaining. 511 * 512 * Unlike [Arrangement.spacedBy], when the layout direction is RTL, the children will not be 513 * mirrored and as such children will appear in the order they are composed inside the 514 * [Row]. 515 * 516 * @param space The space between adjacent children. 517 * @param alignment The alignment of the spaced children inside the parent. 518 */ 519 @Stable 520 fun spacedBy(space: Dp, alignment: Alignment.Horizontal): Horizontal = 521 SpacedAligned(space, false) { size, layoutDirection -> 522 alignment.align(0, size, layoutDirection) 523 } 524 525 /** 526 * Place children vertically such that each two adjacent ones are spaced by a fixed [space] 527 * distance. The spacing will be subtracted from the available height that the children can 528 * occupy. An [alignment] can be specified to align the spaced children vertically inside 529 * the parent, in case there is empty height remaining. 530 * 531 * Unlike [Arrangement.spacedBy], when the layout direction is RTL, the children will not be 532 * mirrored and as such children will appear in the order they are composed inside the 533 * [Row]. 534 * 535 * @param space The space between adjacent children. 536 * @param alignment The alignment of the spaced children inside the parent. 537 */ 538 @Stable 539 fun spacedBy(space: Dp, alignment: Alignment.Vertical): Vertical = 540 SpacedAligned(space, false) { size, _ -> alignment.align(0, size) } 541 542 /** 543 * Place children horizontally one next to the other and align the obtained group according 544 * to an [alignment]. 545 * 546 * Unlike [Arrangement.aligned], when the layout direction is RTL, the children will not be 547 * mirrored and as such children will appear in the order they are composed inside the 548 * [Row]. 549 * 550 * @param alignment The alignment of the children inside the parent. 551 */ 552 @Stable 553 fun aligned(alignment: Alignment.Horizontal): Horizontal = 554 SpacedAligned(0.dp, false) { size, layoutDirection -> 555 alignment.align(0, size, layoutDirection) 556 } 557 } 558 559 /** 560 * Arrangement with spacing between adjacent children and alignment for the spaced group. Should 561 * not be instantiated directly, use [spacedBy] instead. 562 */ 563 @Immutable 564 internal data class SpacedAligned( 565 val space: Dp, 566 val rtlMirror: Boolean, 567 val alignment: ((Int, LayoutDirection) -> Int)? 568 ) : HorizontalOrVertical { 569 570 override val spacing = space 571 572 override fun Density.arrange( 573 totalSize: Int, 574 sizes: IntArray, 575 layoutDirection: LayoutDirection, 576 outPositions: IntArray 577 ) { 578 if (sizes.isEmpty()) return 579 val spacePx = space.roundToPx() 580 581 var occupied = 0 582 var lastSpace = 0 583 val reversed = rtlMirror && layoutDirection == LayoutDirection.Rtl 584 sizes.forEachIndexed(reversed) { index, it -> 585 outPositions[index] = min(occupied, totalSize - it) 586 lastSpace = min(spacePx, totalSize - outPositions[index] - it) 587 occupied = outPositions[index] + it + lastSpace 588 } 589 occupied -= lastSpace 590 591 if (alignment != null && occupied < totalSize) { 592 val groupPosition = alignment.invoke(totalSize - occupied, layoutDirection) 593 for (index in outPositions.indices) { 594 outPositions[index] += groupPosition 595 } 596 } 597 } 598 599 override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) = 600 arrange(totalSize, sizes, LayoutDirection.Ltr, outPositions) 601 602 override fun toString() = 603 "${if (rtlMirror) "" else "Absolute"}Arrangement#spacedAligned($space, $alignment)" 604 } 605 606 internal fun placeRightOrBottom( 607 totalSize: Int, 608 size: IntArray, 609 outPosition: IntArray, 610 reverseInput: Boolean 611 ) { 612 val consumedSize = size.fold(0) { a, b -> a + b } 613 var current = totalSize - consumedSize 614 size.forEachIndexed(reverseInput) { index, it -> 615 outPosition[index] = current 616 current += it 617 } 618 } 619 620 internal fun placeLeftOrTop(size: IntArray, outPosition: IntArray, reverseInput: Boolean) { 621 var current = 0 622 size.forEachIndexed(reverseInput) { index, it -> 623 outPosition[index] = current 624 current += it 625 } 626 } 627 628 internal fun placeCenter( 629 totalSize: Int, 630 size: IntArray, 631 outPosition: IntArray, 632 reverseInput: Boolean 633 ) { 634 val consumedSize = size.fold(0) { a, b -> a + b } 635 var current = (totalSize - consumedSize).toFloat() / 2 636 size.forEachIndexed(reverseInput) { index, it -> 637 outPosition[index] = current.fastRoundToInt() 638 current += it.toFloat() 639 } 640 } 641 642 internal fun placeSpaceEvenly( 643 totalSize: Int, 644 size: IntArray, 645 outPosition: IntArray, 646 reverseInput: Boolean 647 ) { 648 val consumedSize = size.fold(0) { a, b -> a + b } 649 val gapSize = (totalSize - consumedSize).toFloat() / (size.size + 1) 650 var current = gapSize 651 size.forEachIndexed(reverseInput) { index, it -> 652 outPosition[index] = current.fastRoundToInt() 653 current += it.toFloat() + gapSize 654 } 655 } 656 657 internal fun placeSpaceBetween( 658 totalSize: Int, 659 size: IntArray, 660 outPosition: IntArray, 661 reverseInput: Boolean 662 ) { 663 if (size.isEmpty()) return 664 665 val consumedSize = size.fold(0) { a, b -> a + b } 666 val noOfGaps = maxOf(size.lastIndex, 1) 667 val gapSize = (totalSize - consumedSize).toFloat() / noOfGaps 668 669 var current = 0f 670 if (reverseInput && size.size == 1) { 671 // If the layout direction is right-to-left and there is only one gap, 672 // we start current with the gap size. That forces the single item to be right-aligned. 673 current = gapSize 674 } 675 size.forEachIndexed(reverseInput) { index, it -> 676 outPosition[index] = current.fastRoundToInt() 677 current += it.toFloat() + gapSize 678 } 679 } 680 681 internal fun placeSpaceAround( 682 totalSize: Int, 683 size: IntArray, 684 outPosition: IntArray, 685 reverseInput: Boolean 686 ) { 687 val consumedSize = size.fold(0) { a, b -> a + b } 688 val gapSize = 689 if (size.isNotEmpty()) { 690 (totalSize - consumedSize).toFloat() / size.size 691 } else { 692 0f 693 } 694 var current = gapSize / 2 695 size.forEachIndexed(reverseInput) { index, it -> 696 outPosition[index] = current.fastRoundToInt() 697 current += it.toFloat() + gapSize 698 } 699 } 700 701 private inline fun IntArray.forEachIndexed(reversed: Boolean, action: (Int, Int) -> Unit) { 702 if (!reversed) { 703 forEachIndexed(action) 704 } else { 705 for (i in (size - 1) downTo 0) { 706 action(i, get(i)) 707 } 708 } 709 } 710 } 711