or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

composables.mdcore-ui.mdgraphics.mdindex.mdinput.mdios-integration.mdlayout.mdmaterial-design.mdresources.mdstate.mdtext.mdwindow.md

layout.mddocs/

0

# Layout System

1

2

Flexible layout engine with built-in layouts and support for custom layout implementations with precise measurement and positioning control for creating sophisticated user interfaces.

3

4

## Capabilities

5

6

### Custom Layout Foundation

7

8

Core layout system providing the building blocks for creating custom layout composables with precise measurement and positioning control.

9

10

```kotlin { .api }

11

/**

12

* A composable that lays out and draws its children according to a custom measurement and placement policy.

13

*/

14

@Composable

15

fun Layout(

16

content: @Composable () -> Unit,

17

modifier: Modifier = Modifier,

18

measurePolicy: MeasurePolicy

19

)

20

21

/**

22

* A composable that lays out multiple sets of children according to a custom measurement and placement policy.

23

*/

24

@Composable

25

fun MultiMeasureLayout(

26

modifier: Modifier = Modifier,

27

measurePolicy: MultiMeasurePolicy,

28

content: @Composable () -> Unit

29

)

30

31

/**

32

* Policy for measuring and placing children in a Layout composable.

33

*/

34

fun interface MeasurePolicy {

35

/**

36

* Measure and position child composables.

37

*/

38

fun MeasureScope.measure(

39

measurables: List<Measurable>,

40

constraints: Constraints

41

): MeasureResult

42

43

/**

44

* Calculate the minimum intrinsic width.

45

*/

46

fun IntrinsicMeasureScope.minIntrinsicWidth(

47

measurables: List<IntrinsicMeasurable>,

48

height: Int

49

): Int = 0

50

51

/**

52

* Calculate the minimum intrinsic height.

53

*/

54

fun IntrinsicMeasureScope.minIntrinsicHeight(

55

measurables: List<IntrinsicMeasurable>,

56

width: Int

57

): Int = 0

58

59

/**

60

* Calculate the maximum intrinsic width.

61

*/

62

fun IntrinsicMeasureScope.maxIntrinsicWidth(

63

measurables: List<IntrinsicMeasurable>,

64

height: Int

65

): Int = 0

66

67

/**

68

* Calculate the maximum intrinsic height.

69

*/

70

fun IntrinsicMeasureScope.maxIntrinsicHeight(

71

measurables: List<IntrinsicMeasurable>,

72

width: Int

73

): Int = 0

74

}

75

76

/**

77

* The measurement scope used by a Layout's MeasurePolicy.

78

*/

79

interface MeasureScope : IntrinsicMeasureScope {

80

/**

81

* Create a MeasureResult with the specified size and placement block.

82

*/

83

fun layout(

84

width: Int,

85

height: Int,

86

alignmentLines: Map<AlignmentLine, Int> = emptyMap(),

87

placementBlock: Placeable.PlacementScope.() -> Unit

88

): MeasureResult

89

}

90

91

/**

92

* Result of measuring a layout.

93

*/

94

interface MeasureResult {

95

/**

96

* Width of the measured layout.

97

*/

98

val width: Int

99

100

/**

101

* Height of the measured layout.

102

*/

103

val height: Int

104

105

/**

106

* Map of alignment lines to their positions.

107

*/

108

val alignmentLines: Map<AlignmentLine, Int>

109

110

/**

111

* Place children of the layout.

112

*/

113

fun placeChildren()

114

}

115

116

/**

117

* Represents a child composable that can be measured.

118

*/

119

interface Measurable : IntrinsicMeasurable {

120

/**

121

* Measure the child with the given constraints.

122

*/

123

fun measure(constraints: Constraints): Placeable

124

125

/**

126

* Data associated with this measurable.

127

*/

128

val parentData: Any?

129

}

130

131

/**

132

* Represents a measured child that can be placed.

133

*/

134

abstract class Placeable : Measured {

135

/**

136

* Width of the placeable after measurement.

137

*/

138

abstract val width: Int

139

140

/**

141

* Height of the placeable after measurement.

142

*/

143

abstract val height: Int

144

145

/**

146

* Map of alignment lines for this placeable.

147

*/

148

open val alignmentLines: Map<AlignmentLine, Int> = emptyMap()

149

150

/**

151

* Measured size as IntSize.

152

*/

153

val measuredSize: IntSize

154

155

/**

156

* Place the child at the given position.

157

*/

158

protected abstract fun placeAt(

159

position: IntOffset,

160

zIndex: Float,

161

layerBlock: (GraphicsLayerScope.() -> Unit)?

162

)

163

164

/**

165

* Place the child at the given coordinates.

166

*/

167

fun place(x: Int, y: Int) {

168

place(IntOffset(x, y))

169

}

170

171

/**

172

* Place the child at the given offset.

173

*/

174

fun place(position: IntOffset) {

175

placeAt(position, 0f, null)

176

}

177

178

/**

179

* Place the child with a z-index for layering.

180

*/

181

fun placeWithLayer(

182

position: IntOffset,

183

zIndex: Float = 0f,

184

layerBlock: GraphicsLayerScope.() -> Unit = {}

185

) {

186

placeAt(position, zIndex, layerBlock)

187

}

188

189

/**

190

* Place the child relative to the layout direction.

191

*/

192

fun placeRelative(x: Int, y: Int) {

193

placeRelative(IntOffset(x, y))

194

}

195

196

/**

197

* Place the child relative to the layout direction.

198

*/

199

fun placeRelative(position: IntOffset) {

200

placeRelativeAt(position, 0f, null)

201

}

202

203

/**

204

* The scope for placing children.

205

*/

206

abstract class PlacementScope {

207

/**

208

* The layout direction for placing children.

209

*/

210

protected abstract val parentLayoutDirection: LayoutDirection

211

212

/**

213

* The width of the parent layout.

214

*/

215

protected abstract val parentWidth: Int

216

217

/**

218

* Convert coordinates based on layout direction.

219

*/

220

protected fun Placeable.placeRelativeAt(

221

position: IntOffset,

222

zIndex: Float,

223

layerBlock: (GraphicsLayerScope.() -> Unit)?

224

)

225

}

226

}

227

```

228

229

**Usage Examples:**

230

231

```kotlin

232

// Simple custom layout that arranges children vertically

233

@Composable

234

fun SimpleColumn(

235

modifier: Modifier = Modifier,

236

content: @Composable () -> Unit

237

) {

238

Layout(

239

content = content,

240

modifier = modifier

241

) { measurables, constraints ->

242

// Measure all children with available width

243

val placeables = measurables.map { measurable ->

244

measurable.measure(constraints.copy(minHeight = 0))

245

}

246

247

// Calculate total height

248

val totalHeight = placeables.sumOf { it.height }

249

val maxWidth = placeables.maxOfOrNull { it.width } ?: 0

250

251

// Return layout result

252

layout(maxWidth, totalHeight) {

253

var yPosition = 0

254

placeables.forEach { placeable ->

255

placeable.place(x = 0, y = yPosition)

256

yPosition += placeable.height

257

}

258

}

259

}

260

}

261

262

// Custom layout with alignment

263

@Composable

264

fun AlignedLayout(

265

alignment: Alignment.Horizontal,

266

modifier: Modifier = Modifier,

267

content: @Composable () -> Unit

268

) {

269

Layout(

270

content = content,

271

modifier = modifier

272

) { measurables, constraints ->

273

val placeables = measurables.map { it.measure(constraints) }

274

275

val maxWidth = placeables.maxOfOrNull { it.width } ?: 0

276

val totalHeight = placeables.sumOf { it.height }

277

278

layout(maxWidth, totalHeight) {

279

var yPosition = 0

280

placeables.forEach { placeable ->

281

val xPosition = alignment.align(

282

size = placeable.width,

283

space = maxWidth,

284

layoutDirection = layoutDirection

285

)

286

placeable.place(x = xPosition, y = yPosition)

287

yPosition += placeable.height

288

}

289

}

290

}

291

}

292

```

293

294

### Layout Constraints

295

296

Constraint system for defining size requirements and limitations during layout measurement.

297

298

```kotlin { .api }

299

/**

300

* Immutable constraints for measuring child layouts.

301

*/

302

@Immutable

303

data class Constraints(

304

val minWidth: Int = 0,

305

val maxWidth: Int = Infinity,

306

val minHeight: Int = 0,

307

val maxHeight: Int = Infinity

308

) {

309

init {

310

require(minWidth >= 0 && minHeight >= 0) { "minWidth and minHeight must be >= 0" }

311

require(maxWidth >= minWidth) { "maxWidth must be >= minWidth" }

312

require(maxHeight >= minHeight) { "maxHeight must be >= minHeight" }

313

}

314

315

companion object {

316

/**

317

* A value that represents positive infinity for constraints.

318

*/

319

const val Infinity = Int.MAX_VALUE

320

321

/**

322

* Constraints with fixed width and height.

323

*/

324

fun fixed(width: Int, height: Int): Constraints

325

326

/**

327

* Constraints with fixed width.

328

*/

329

fun fixedWidth(width: Int): Constraints

330

331

/**

332

* Constraints with fixed height.

333

*/

334

fun fixedHeight(height: Int): Constraints

335

}

336

337

/**

338

* Whether the constraints allow only a single width value.

339

*/

340

val hasBoundedWidth: Boolean

341

342

/**

343

* Whether the constraints allow only a single height value.

344

*/

345

val hasBoundedHeight: Boolean

346

347

/**

348

* Whether there is exactly one width value that satisfies the constraints.

349

*/

350

val hasFixedWidth: Boolean

351

352

/**

353

* Whether there is exactly one height value that satisfies the constraints.

354

*/

355

val hasFixedHeight: Boolean

356

357

/**

358

* Whether the constraints specify bounded dimensions.

359

*/

360

val isZero: Boolean

361

362

/**

363

* Coerces width within the constraints.

364

*/

365

fun constrainWidth(width: Int): Int

366

367

/**

368

* Coerces height within the constraints.

369

*/

370

fun constrainHeight(height: Int): Int

371

372

/**

373

* Create new constraints by changing individual values.

374

*/

375

fun copy(

376

minWidth: Int = this.minWidth,

377

maxWidth: Int = this.maxWidth,

378

minHeight: Int = this.minHeight,

379

maxHeight: Int = this.maxHeight

380

): Constraints

381

382

/**

383

* Returns the result of coercing the given size within the constraints.

384

*/

385

fun constrain(size: IntSize): IntSize

386

387

/**

388

* Returns constraints with the width constrained between the given values.

389

*/

390

fun constrainWidth(minWidth: Int = this.minWidth, maxWidth: Int = this.maxWidth): Constraints

391

392

/**

393

* Returns constraints with the height constrained between the given values.

394

*/

395

fun constrainHeight(minHeight: Int = this.minHeight, maxHeight: Int = this.maxHeight): Constraints

396

397

/**

398

* Returns the maximum size that fits these constraints.

399

*/

400

val maxSize: IntSize

401

402

/**

403

* Returns the minimum size that fits these constraints.

404

*/

405

val minSize: IntSize

406

}

407

```

408

409

**Usage Examples:**

410

411

```kotlin

412

// Working with constraints in custom layouts

413

@Composable

414

fun ConstraintAwareLayout(

415

modifier: Modifier = Modifier,

416

content: @Composable () -> Unit

417

) {

418

Layout(

419

content = content,

420

modifier = modifier

421

) { measurables, constraints ->

422

// Check constraint properties

423

val hasFixedWidth = constraints.hasFixedWidth

424

val hasBoundedHeight = constraints.hasBoundedHeight

425

426

// Create modified constraints for children

427

val childConstraints = constraints.copy(

428

minWidth = 0,

429

minHeight = 0,

430

maxWidth = if (constraints.hasBoundedWidth) constraints.maxWidth / 2 else Constraints.Infinity

431

)

432

433

// Measure children with modified constraints

434

val placeables = measurables.map { measurable ->

435

measurable.measure(childConstraints)

436

}

437

438

// Calculate layout size respecting constraints

439

val totalWidth = placeables.sumOf { it.width }

440

val maxHeight = placeables.maxOfOrNull { it.height } ?: 0

441

442

val layoutWidth = constraints.constrainWidth(totalWidth)

443

val layoutHeight = constraints.constrainHeight(maxHeight)

444

445

layout(layoutWidth, layoutHeight) {

446

var xPosition = 0

447

placeables.forEach { placeable ->

448

placeable.place(x = xPosition, y = 0)

449

xPosition += placeable.width

450

}

451

}

452

}

453

}

454

455

// Fixed size constraints

456

val fixedConstraints = Constraints.fixed(width = 200, height = 100)

457

458

// Flexible constraints with limits

459

val flexibleConstraints = Constraints(

460

minWidth = 100,

461

maxWidth = 300,

462

minHeight = 50,

463

maxHeight = Constraints.Infinity

464

)

465

```

466

467

### Intrinsic Measurements

468

469

System for querying preferred dimensions of composables before final measurement and layout.

470

471

```kotlin { .api }

472

/**

473

* Interface for calculating intrinsic measurements.

474

*/

475

interface IntrinsicMeasurable {

476

/**

477

* Data from parent layout.

478

*/

479

val parentData: Any?

480

481

/**

482

* Calculate the minimum width for the given height.

483

*/

484

fun minIntrinsicWidth(height: Int): Int

485

486

/**

487

* Calculate the maximum width for the given height.

488

*/

489

fun maxIntrinsicWidth(height: Int): Int

490

491

/**

492

* Calculate the minimum height for the given width.

493

*/

494

fun minIntrinsicHeight(width: Int): Int

495

496

/**

497

* Calculate the maximum height for the given width.

498

*/

499

fun maxIntrinsicHeight(width: Int): Int

500

}

501

502

/**

503

* Scope for intrinsic measurement calculations.

504

*/

505

interface IntrinsicMeasureScope : Density {

506

/**

507

* The layout direction for intrinsic calculations.

508

*/

509

val layoutDirection: LayoutDirection

510

}

511

512

/**

513

* Marker interface for measured layouts.

514

*/

515

interface Measured {

516

/**

517

* The measured width.

518

*/

519

val measuredWidth: Int

520

521

/**

522

* The measured height.

523

*/

524

val measuredHeight: Int

525

526

/**

527

* Get the position of an alignment line, or AlignmentLine.Unspecified.

528

*/

529

operator fun get(alignmentLine: AlignmentLine): Int

530

}

531

```

532

533

**Usage Examples:**

534

535

```kotlin

536

// Layout using intrinsic measurements

537

@Composable

538

fun IntrinsicAwareLayout(

539

modifier: Modifier = Modifier,

540

content: @Composable () -> Unit

541

) {

542

Layout(

543

content = content,

544

modifier = modifier,

545

measurePolicy = object : MeasurePolicy {

546

override fun MeasureScope.measure(

547

measurables: List<Measurable>,

548

constraints: Constraints

549

): MeasureResult {

550

// Query intrinsic sizes before measuring

551

val minIntrinsicWidth = measurables.sumOf {

552

it.minIntrinsicWidth(Constraints.Infinity)

553

}

554

val maxIntrinsicHeight = measurables.maxOfOrNull {

555

it.maxIntrinsicHeight(constraints.maxWidth)

556

} ?: 0

557

558

// Use intrinsic information to make measurement decisions

559

val childConstraints = if (minIntrinsicWidth <= constraints.maxWidth) {

560

constraints.copy(minWidth = 0)

561

} else {

562

constraints.copy(maxWidth = constraints.maxWidth / measurables.size)

563

}

564

565

val placeables = measurables.map { measurable ->

566

measurable.measure(childConstraints)

567

}

568

569

val layoutWidth = constraints.constrainWidth(

570

placeables.sumOf { it.width }

571

)

572

val layoutHeight = constraints.constrainHeight(

573

placeables.maxOfOrNull { it.height } ?: 0

574

)

575

576

layout(layoutWidth, layoutHeight) {

577

var xPosition = 0

578

placeables.forEach { placeable ->

579

placeable.place(x = xPosition, y = 0)

580

xPosition += placeable.width

581

}

582

}

583

}

584

585

override fun IntrinsicMeasureScope.minIntrinsicWidth(

586

measurables: List<IntrinsicMeasurable>,

587

height: Int

588

): Int {

589

return measurables.sumOf { it.minIntrinsicWidth(height) }

590

}

591

592

override fun IntrinsicMeasureScope.maxIntrinsicWidth(

593

measurables: List<IntrinsicMeasurable>,

594

height: Int

595

): Int {

596

return measurables.sumOf { it.maxIntrinsicWidth(height) }

597

}

598

}

599

)

600

}

601

602

// Using intrinsic size modifiers

603

@Composable

604

fun IntrinsicExample() {

605

Column {

606

// Width based on intrinsic measurements

607

Row(

608

modifier = Modifier.width(IntrinsicSize.Max)

609

) {

610

Text("Short", modifier = Modifier.fillMaxHeight())

611

Text("Much longer text", modifier = Modifier.fillMaxHeight())

612

}

613

614

// Height based on intrinsic measurements

615

Column(

616

modifier = Modifier.height(IntrinsicSize.Min)

617

) {

618

Text("Line 1")

619

Text("Line 2 with more content")

620

}

621

}

622

}

623

```

624

625

### Layout Events and Callbacks

626

627

System for responding to layout changes, positioning updates, and size modifications.

628

629

```kotlin { .api }

630

/**

631

* Modifier that provides callback for global position changes.

632

*/

633

fun Modifier.onGloballyPositioned(

634

onGloballyPositioned: (LayoutCoordinates) -> Unit

635

): Modifier

636

637

/**

638

* Modifier that provides callback for size changes.

639

*/

640

fun Modifier.onSizeChanged(

641

onSizeChanged: (IntSize) -> Unit

642

): Modifier

643

644

/**

645

* Modifier that provides callback for placement changes.

646

*/

647

fun Modifier.onPlaced(

648

onPlaced: (LayoutCoordinates) -> Unit

649

): Modifier

650

651

/**

652

* A coordinate system for a layout.

653

*/

654

interface LayoutCoordinates {

655

/**

656

* The size of this layout in the local coordinate system.

657

*/

658

val size: IntSize

659

660

/**

661

* Whether this coordinate system is attached to the root of the composition.

662

*/

663

val isAttached: Boolean

664

665

/**

666

* The LayoutCoordinates of the parent layout modifier or parent layout.

667

*/

668

val parentLayoutCoordinates: LayoutCoordinates?

669

670

/**

671

* The LayoutCoordinates of the parent composable.

672

*/

673

val parentCoordinates: LayoutCoordinates?

674

675

/**

676

* Converts a local position to an ancestor coordinate system.

677

*/

678

fun localToWindow(relativeToLocal: Offset): Offset

679

680

/**

681

* Converts a local position to the root coordinate system.

682

*/

683

fun localToRoot(relativeToLocal: Offset): Offset

684

685

/**

686

* Converts a position in the ancestor coordinate system to local.

687

*/

688

fun windowToLocal(relativeToWindow: Offset): Offset

689

690

/**

691

* Converts a position in the root coordinate system to local.

692

*/

693

fun rootToLocal(relativeToRoot: Offset): Offset

694

695

/**

696

* Converts a local position to the coordinate system of another layout.

697

*/

698

fun localPositionOf(

699

sourceCoordinates: LayoutCoordinates,

700

relativeToSource: Offset

701

): Offset

702

703

/**

704

* Converts a local bounding box to the coordinate system of another layout.

705

*/

706

fun localBoundingBoxOf(

707

sourceCoordinates: LayoutCoordinates,

708

clipBounds: Boolean = true

709

): Rect

710

711

/**

712

* Gets the position of an alignment line in the local coordinate system.

713

*/

714

operator fun get(alignmentLine: AlignmentLine): Int

715

}

716

717

/**

718

* Intrinsic size values for width and height constraints.

719

*/

720

enum class IntrinsicSize { Min, Max }

721

722

/**

723

* Modifier for setting intrinsic size constraints.

724

*/

725

fun Modifier.width(intrinsicSize: IntrinsicSize): Modifier

726

fun Modifier.height(intrinsicSize: IntrinsicSize): Modifier

727

fun Modifier.requiredWidth(intrinsicSize: IntrinsicSize): Modifier

728

fun Modifier.requiredHeight(intrinsicSize: IntrinsicSize): Modifier

729

```

730

731

**Usage Examples:**

732

733

```kotlin

734

// Responding to layout position changes

735

@Composable

736

fun PositionAwareBox() {

737

var position by remember { mutableStateOf(Offset.Zero) }

738

var size by remember { mutableStateOf(IntSize.Zero) }

739

740

Box(

741

modifier = Modifier

742

.size(200.dp)

743

.background(Color.Blue)

744

.onGloballyPositioned { coordinates ->

745

position = coordinates.localToRoot(Offset.Zero)

746

size = coordinates.size

747

}

748

.onSizeChanged { newSize ->

749

// React to size changes

750

println("Size changed to: $newSize")

751

}

752

) {

753

Text(

754

text = "Position: (${position.x.toInt()}, ${position.y.toInt()})\nSize: ${size.width} x ${size.height}",

755

color = Color.White,

756

modifier = Modifier.align(Alignment.Center)

757

)

758

}

759

}

760

761

// Coordinate system conversions

762

@Composable

763

fun CoordinateExample() {

764

var clickPosition by remember { mutableStateOf(Offset.Zero) }

765

766

Box(

767

modifier = Modifier

768

.fillMaxSize()

769

.onGloballyPositioned { rootCoordinates ->

770

// Store root coordinates for conversions

771

}

772

.pointerInput(Unit) {

773

detectTapGestures { tapOffset ->

774

clickPosition = tapOffset

775

}

776

}

777

) {

778

Box(

779

modifier = Modifier

780

.size(100.dp)

781

.background(Color.Red)

782

.align(Alignment.Center)

783

.onGloballyPositioned { childCoordinates ->

784

// Convert click position to child coordinate system

785

val localPosition = childCoordinates.windowToLocal(clickPosition)

786

if (childCoordinates.size.toRect().contains(localPosition)) {

787

println("Clicked inside child at local position: $localPosition")

788

}

789

}

790

)

791

}

792

}

793

```

794

795

### Parent Data and Layout Parameters

796

797

System for passing layout-specific data from child to parent composables during layout.

798

799

```kotlin { .api }

800

/**

801

* Modifier for attaching parent data to a layout.

802

*/

803

fun Modifier.parentData(parentData: Any?): Modifier

804

805

/**

806

* Marker interface for parent data classes.

807

*/

808

interface ParentDataModifier : Modifier.Element {

809

/**

810

* Modify the parent data.

811

*/

812

fun Density.modifyParentData(parentData: Any?): Any?

813

}

814

815

/**

816

* Alignment lines for coordinating layout alignment.

817

*/

818

abstract class AlignmentLine(internal val merger: (Int, Int) -> Int) {

819

companion object {

820

/**

821

* Unspecified alignment line position.

822

*/

823

const val Unspecified: Int = Int.MIN_VALUE

824

}

825

}

826

827

/**

828

* Horizontal alignment line.

829

*/

830

abstract class HorizontalAlignmentLine(merger: (Int, Int) -> Int) : AlignmentLine(merger)

831

832

/**

833

* Vertical alignment line.

834

*/

835

abstract class VerticalAlignmentLine(merger: (Int, Int) -> Int) : AlignmentLine(merger)

836

837

/**

838

* Common alignment lines.

839

*/

840

object AlignmentLineOffset {

841

/**

842

* First baseline of text.

843

*/

844

val FirstBaseline: HorizontalAlignmentLine

845

846

/**

847

* Last baseline of text.

848

*/

849

val LastBaseline: HorizontalAlignmentLine

850

}

851

852

/**

853

* Modifier for providing alignment lines.

854

*/

855

fun Modifier.alignmentLineOffset(

856

alignmentLine: AlignmentLine,

857

before: Dp = 0.dp,

858

after: Dp = 0.dp

859

): Modifier

860

861

/**

862

* Modifier for aligning by a baseline.

863

*/

864

fun Modifier.alignBy(alignmentLine: HorizontalAlignmentLine): Modifier

865

fun Modifier.alignBy(alignmentLineBlock: (Measured) -> Int): Modifier

866

```

867

868

**Usage Examples:**

869

870

```kotlin

871

// Custom parent data for layout parameters

872

data class FlexChildData(

873

val flex: Float,

874

val alignment: Alignment.Vertical? = null

875

)

876

877

fun Modifier.flex(flex: Float, alignment: Alignment.Vertical? = null) = this.then(

878

object : ParentDataModifier {

879

override fun Density.modifyParentData(parentData: Any?): FlexChildData {

880

return FlexChildData(flex, alignment)

881

}

882

}

883

)

884

885

@Composable

886

fun FlexLayout(

887

modifier: Modifier = Modifier,

888

content: @Composable () -> Unit

889

) {

890

Layout(

891

content = content,

892

modifier = modifier

893

) { measurables, constraints ->

894

// Access parent data from children

895

val flexData = measurables.map { measurable ->

896

(measurable.parentData as? FlexChildData) ?: FlexChildData(flex = 1f)

897

}

898

899

val totalFlex = flexData.sumOf { it.flex.toDouble() }.toFloat()

900

val availableWidth = constraints.maxWidth

901

902

val placeables = measurables.mapIndexed { index, measurable ->

903

val flex = flexData[index].flex

904

val childWidth = ((availableWidth * flex) / totalFlex).toInt()

905

906

measurable.measure(

907

constraints.copy(

908

minWidth = childWidth,

909

maxWidth = childWidth

910

)

911

)

912

}

913

914

val maxHeight = placeables.maxOfOrNull { it.height } ?: 0

915

916

layout(availableWidth, maxHeight) {

917

var xPosition = 0

918

placeables.forEachIndexed { index, placeable ->

919

val alignment = flexData[index].alignment ?: Alignment.CenterVertically

920

val yPosition = alignment.align(placeable.height, maxHeight)

921

922

placeable.place(x = xPosition, y = yPosition)

923

xPosition += placeable.width

924

}

925

}

926

}

927

}

928

929

// Using the flex layout

930

@Composable

931

fun FlexExample() {

932

FlexLayout(

933

modifier = Modifier.fillMaxWidth()

934

) {

935

Box(

936

modifier = Modifier

937

.flex(1f, Alignment.Top)

938

.height(50.dp)

939

.background(Color.Red)

940

)

941

Box(

942

modifier = Modifier

943

.flex(2f, Alignment.CenterVertically)

944

.height(100.dp)

945

.background(Color.Green)

946

)

947

Box(

948

modifier = Modifier

949

.flex(1f, Alignment.Bottom)

950

.height(75.dp)

951

.background(Color.Blue)

952

)

953

}

954

}

955

956

// Alignment line example

957

@Composable

958

fun BaselineAlignedRow() {

959

Row {

960

Text(

961

text = "Small",

962

fontSize = 12.sp,

963

modifier = Modifier.alignBy(FirstBaseline)

964

)

965

Text(

966

text = "Large",

967

fontSize = 24.sp,

968

modifier = Modifier.alignBy(FirstBaseline)

969

)

970

Text(

971

text = "Medium",

972

fontSize = 18.sp,

973

modifier = Modifier.alignBy(FirstBaseline)

974

)

975

}

976

}

977

```