---
title: 'Düzen Bileşenleri'
source: 'https://academia.sh/tr/kurslar/flutter/duzen-bilesenleri'
course: Flutter
language: tr
updated: '2026-10-21T05:02:52+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Sütunun ve satırın çocuklarına hangi kısıtı verdiğini açıklar'
    - 'Sıkı ve gevşek esnek çocuğun payı nasıl kullandığını ayırt eder'
    - 'Esnek çocuk olmanın içindeki bileşenin esnetilen olması anlamına gelmediğini ölçer'
---

# Düzen Bileşenleri

Sütun, satır ve esnek çocuk, kısıtı aşağı geçiren düzen bileşenleridir. Ders sıkı ve gevşek esnek çocuğu ayırır ve esnek bir çocuk olmanın içindeki bileşeni esnetilen yapmadığını ölçerek gösterir.

Önceki derste çizim nesnesi ağacının kısıtı aşağı geçirdiğini gördük. Bu geçişi ağaçta en çok **düzen bileşenleri** yapar: sütun, satır ve esnek çocuk. Bu bileşenlerin kendileri ekranda bir şey göstermez; çocuklarına hangi aralığın verileceğine karar verirler.

## Sütun ve Satır

**Sütun**, çocuklarını alt alta dizer. Kendisine gelen kısıtı gevşetir ve her çocuğa `0..en büyük` aralığını verir. Kendi genişliği, çocuklarının en genişidir.

**Satır**, çocuklarını yan yana dizer. Burada fark vardır: satırın genişliği çocuklar arasında paylaşılır. Esnek olmayan çocuğa `0..sonsuz` verilir, yani çocuk istediği kadar geniş olabilir. Esnek çocuklar ise geriye kalan payı paylaşır. Dersin çekirdeği yine ilk dersin `sizing.dart` dosyasıdır.

```dart
// sizing.dart — bir bilesenin genisligini kimin belirledigini siniflandirir
const sizings = ['dayatilan', 'secilen', 'kirpilan', 'esnetilen'];

class Limit {
  final int min;
  final int? max; // null: sinirsiz
  const Limit(this.min, this.max);

  bool get tight => max == min;
  Limit loosen() => Limit(0, max);
  Limit deflate(int by) => Limit(_floor(min - by), max == null ? null : _floor(max! - by));
  String bounds() => '$min..${max ?? 'sonsuz'}';
}

int _floor(int value) => value < 0 ? 0 : value;

class Part {
  final String kind;
  final String name;
  final int? width; // null: alabildigi kadar genis
  final List<Part> children;
  final int factor;
  final bool tightFlex;
  const Part(this.kind, this.name, this.width, this.children,
      {this.factor = 0, this.tightFlex = true});
}

Part leaf(String name, int width) => Part('leaf', name, width, const []);
Part fill(String name) => Part('leaf', name, null, const []);
Part pad(String name, int padding, Part child) => Part('pad', name, padding, [child]);
Part center(String name, Part child) => Part('center', name, null, [child]);
Part fixed(String name, int width, Part child) => Part('fixed', name, width, [child]);
Part column(String name, List<Part> children) => Part('column', name, null, children);
Part row(String name, List<Part> children) => Part('row', name, null, children);
Part flex(String name, int factor, Part child, {bool tight = true}) =>
    Part('flex', name, null, [child], factor: factor, tightFlex: tight);

class Sizing {
  final String sizing;
  final String path;
  final int width;
  final Limit limit;
  const Sizing(this.sizing, this.path, this.width, this.limit);
}

Sizing classify(String path, int? desire, Limit limit) {
  if (limit.tight) return Sizing('dayatilan', path, limit.min, limit);
  if (desire == null) {
    return limit.max == null
        ? Sizing('kirpilan', path, limit.min, limit)
        : Sizing('esnetilen', path, limit.max!, limit);
  }
  if (desire < limit.min) return Sizing('kirpilan', path, limit.min, limit);
  if (limit.max != null && desire > limit.max!) {
    return Sizing('kirpilan', path, limit.max!, limit);
  }
  return Sizing('secilen', path, desire, limit);
}

int layout(Part part, Limit limit, List<Sizing> log, [String path = '']) {
  final here = '$path/${part.name}';
  final below = <Sizing>[];
  if (part.kind == 'fixed') {
    final own = classify(here, part.width, limit);
    layout(part.children.first, Limit(own.width, own.width), below, here);
    log..add(own)..addAll(below);
    return own.width;
  }
  int? desire;
  switch (part.kind) {
    case 'leaf':
      desire = part.width;
    case 'pad':
      final space = 2 * part.width!;
      desire = layout(part.children.first, limit.deflate(space), below, here) + space;
    case 'center':
      final inner = layout(part.children.first, limit.loosen(), below, here);
      desire = limit.max == null ? inner : null;
    case 'flex':
      desire = layout(part.children.first, limit, below, here);
    case 'column':
      var widest = 0;
      for (final child in part.children) {
        final width = layout(child, limit.loosen(), below, here);
        if (width > widest) widest = width;
      }
      desire = widest;
    case 'row':
      final logs = [for (final _ in part.children) <Sizing>[]];
      final bounded = limit.max != null;
      var used = 0;
      var factors = 0;
      for (var i = 0; i < part.children.length; i++) {
        final child = part.children[i];
        if (child.kind == 'flex' && bounded) {
          factors += child.factor;
        } else {
          used += layout(child, const Limit(0, null), logs[i], here);
        }
      }
      final left = bounded ? _floor(limit.max! - used) : 0;
      var given = 0;
      var seen = 0;
      for (var i = 0; i < part.children.length; i++) {
        final child = part.children[i];
        if (child.kind != 'flex' || !bounded) continue;
        seen += child.factor;
        final share = (seen == factors ? left : left * seen ~/ factors) - given;
        given += share;
        final room = child.tightFlex ? Limit(share, share) : Limit(0, share);
        used += layout(child, room, logs[i], here);
      }
      for (final entries in logs) {
        below.addAll(entries);
      }
      desire = bounded ? null : used;
  }
  final own = classify(here, desire, limit);
  log..add(own)..addAll(below);
  return own.width;
}

List<Sizing> measure(Part root, int screen) {
  final log = <Sizing>[];
  layout(root, Limit(screen, screen), log);
  return log;
}

void printSizes(List<Sizing> log) {
  for (final entry in log) {
    print('${entry.sizing}: ${entry.path} genislik=${entry.width} kisit=${entry.limit.bounds()}');
  }
}

void countSizings(List<Sizing> log) {
  for (final name in sizings) {
    print('$name: ${log.where((entry) => entry.sizing == name).length}');
  }
  print('ebeveyn: ${log.where((entry) => entry.sizing != 'secilen').length}');
}
```

**DB1.** Modelde satır, esnek olmayan çocukları önce yerleştirir, kalan payı sonra esnek çocuklara dağıtır. Çerçevenin ana eksen hizalama ve ikinci eksen seçenekleri modellenmez; model yalnız genişliği ölçer.

## Esnek Çocuk

Esnek çocuk, satırın kalan payından bir dilim alan çocuktur. Dilimin büyüklüğünü **esneklik çarpanı** belirler: çarpanı 2 olan çocuk, çarpanı 1 olandan iki kat pay alır. Çerçevede esnek çocuk iki biçimdedir ve fark, payı nasıl kullandıklarındadır.

```dart
// Platform kodu: esnek cocuklar
Row(
  children: [
    const Icon(Icons.person),
    const Expanded(child: Text('Ad Soyad')),
    const Flexible(child: Text('Not')),
  ],
)
```

`Expanded` çocuğa payın tamamını **sıkı** olarak verir: çocuk payı mutlaka doldurur. `Flexible` ise payı **gevşek** verir: çocuk payın içinde istediği genişliği seçer ve daha azını alabilir. Modeldeki karşılıkları `flex(..., tight: true)` ve `flex(..., tight: false)` çağrılarıdır.

**DB2.** Modelde esnek çocuk, çarpanı ve sıkı ya da gevşek oluşu dışında hiçbir şey bilmez. Çerçevenin esnek çocuğa uyguladığı başka bir kuralı, örneğin taşma davranışını, model içermez.

### Sıkı Esnek Çocuk

Bir satırda soldaki simge sabit 48 genişliğinde, yanındaki ad ise sıkı esnek çocuktur.

```dart
// main.dart
import 'sizing.dart';

void main() {
  final tree = pad('Screen', 16, row('Line', [
    fixed('Icon', 48, leaf('Glyph', 48)),
    flex('Name', 1, fill('Text')),
  ]));
  printSizes(measure(tree, 360));
}
```

```text
dayatilan: /Screen genislik=360 kisit=360..360
dayatilan: /Screen/Line genislik=328 kisit=328..328
secilen: /Screen/Line/Icon genislik=48 kisit=0..sonsuz
dayatilan: /Screen/Line/Icon/Glyph genislik=48 kisit=48..48
dayatilan: /Screen/Line/Name genislik=280 kisit=280..280
dayatilan: /Screen/Line/Name/Text genislik=280 kisit=280..280
```

Satır önce esnek olmayan çocuğu yerleştirir: `Icon` 48 ister ve 48'i seçer. Geriye 328 eksi 48, yani 280 kalır. Tek esnek çocuk olan `Name` payın tamamını sıkı olarak alır. Sıkı bir kısıt, çocuğun isteği ne olursa olsun genişliği belirler; bu yüzden hem `Name` hem de içindeki `Text` dayatılandır.

### Gevşek Esnek Çocuk

Şimdi aynı satırda ad yerine gevşek bir esnek çocuk koyalım.

```dart
// main.dart
import 'sizing.dart';

void main() {
  final tree = pad('Screen', 16, row('Line', [
    fixed('Icon', 48, leaf('Glyph', 48)),
    flex('Note', 1, fill('Text'), tight: false),
  ]));
  printSizes(measure(tree, 360));
}
```

```text
dayatilan: /Screen genislik=360 kisit=360..360
dayatilan: /Screen/Line genislik=328 kisit=328..328
secilen: /Screen/Line/Icon genislik=48 kisit=0..sonsuz
dayatilan: /Screen/Line/Icon/Glyph genislik=48 kisit=48..48
secilen: /Screen/Line/Note genislik=280 kisit=0..280
esnetilen: /Screen/Line/Note/Text genislik=280 kisit=0..280
```

Pay yine 280'dir ama bu kez `Note`'a `0..280` olarak verilir. `Text` istek bildirmediği için üst sınırı doldurur ve **esnetilen** olur. `Note` ise çocuğunun bildirdiği 280'i aralığın içinde seçilmiş bir değer olarak alır: **seçilen**. Esnek çocuk olan `Note`'un kendisi esnetilen değildir; esnetilen, onun içindeki `Text`'tir.

Gevşek çocuğun içi istek bildiren bir yaprak olursa durum değişir.

```dart
// main.dart
import 'sizing.dart';

void main() {
  final tree = pad('Screen', 16, row('Line', [
    fixed('Icon', 48, leaf('Glyph', 48)),
    flex('Note', 1, leaf('Text', 120), tight: false),
  ]));
  printSizes(measure(tree, 360));
}
```

```text
dayatilan: /Screen genislik=360 kisit=360..360
dayatilan: /Screen/Line genislik=328 kisit=328..328
secilen: /Screen/Line/Icon genislik=48 kisit=0..sonsuz
dayatilan: /Screen/Line/Icon/Glyph genislik=48 kisit=48..48
secilen: /Screen/Line/Note genislik=120 kisit=0..280
secilen: /Screen/Line/Note/Text genislik=120 kisit=0..280
```

`Text` 120 ister ve `0..280` aralığında 120'yi seçer; `Note` da çocuğu kadar, yani 120 kadar yer alır. Pay 280 olmasına rağmen ikisi de 120'de kalır. Gevşek esnek çocuk payı kullanma hakkı verir, kullanma zorunluluğu getirmez.

Bu üç ölçüm bir ayrımı gösterir: **esnek çocuk olmak ile esnetilen olmak aynı şey değildir.** Esnek çocuk, satırın bir yerleşim rolüdür. Esnetilen ise bir düğümün genişliğini nasıl aldığını anlatan bir sınıftır: istek yok, üst sınır sonlu ve düğüm onu dolduruyor. Sıkı esnek çocuk dayatılan, gevşek esnek çocuk seçilen çıktı; esnetilen olan, gevşek çocuğun içindeki isteksiz yapraktı.

## Sınırlayıcı Ölçüm

Odak düğüm, gevşek esnek çocuğun içindeki metindir: `/Screen/Line/Note/Text`. Aynı satırı iki ekran genişliğinde ölçelim.

```dart
// main.dart
import 'sizing.dart';

void main() {
  for (final width in [480, 320]) {
    print('ekran: $width');
    final tree = pad('Screen', 16, row('Line', [
      fixed('Icon', 48, leaf('Glyph', 48)),
      flex('Note', 1, fill('Text'), tight: false),
    ]));
    printSizes(measure(tree, width));
  }
}
```

```text
ekran: 480
dayatilan: /Screen genislik=480 kisit=480..480
dayatilan: /Screen/Line genislik=448 kisit=448..448
secilen: /Screen/Line/Icon genislik=48 kisit=0..sonsuz
dayatilan: /Screen/Line/Icon/Glyph genislik=48 kisit=48..48
secilen: /Screen/Line/Note genislik=400 kisit=0..400
esnetilen: /Screen/Line/Note/Text genislik=400 kisit=0..400
ekran: 320
dayatilan: /Screen genislik=320 kisit=320..320
dayatilan: /Screen/Line genislik=288 kisit=288..288
secilen: /Screen/Line/Icon genislik=48 kisit=0..sonsuz
dayatilan: /Screen/Line/Icon/Glyph genislik=48 kisit=48..48
secilen: /Screen/Line/Note genislik=240 kisit=0..240
esnetilen: /Screen/Line/Note/Text genislik=240 kisit=0..240
```

**Bu dersin boyutlanması: esnetilen.** `/Screen/Line/Note/Text` istek bildirmez, üst sınırı sonludur ve onu doldurur: 480 ekranda 400, 320 ekranda 240. Genişliği ne `Text`'in isteği ne de kendi seçimi belirler; ebeveyninin payı belirler. `Note` ise ikisinde de seçilendir, çünkü çocuğunun bildirdiği genişlik aralığın içinde kalır.

## Özet

- Bu dersin boyutlanması: esnetilen. Gevşek esnek çocuğun içindeki metin istek bildirmez ve payı doldurur: 360 ekranda 280, 480 ekranda 400, 320 ekranda 240.
- Sütun kısıtı gevşetir ve çocuklarının en genişini kendi genişliği yapar; satır esnek olmayan çocuklara `0..sonsuz` verir, kalan payı esnek çocuklara dağıtır.
- Sıkı esnek çocuk payın tamamını sıkı kısıt olarak alır ve dayatılan olur; gevşek esnek çocuk payı üst sınır olarak alır.
- Gevşek esnek çocuğun içi sabit bir yaprak olursa pay boşta kalır; çocuk seçilen olur.
- Esnek çocuk olmak bir yerleşim rolüdür; esnetilen olmak ise genişliğin nasıl alındığının sınıfıdır. İkisi aynı şey değildir.

## Sonraki Adım

Bu konunun son dersi, aynı arayüzü farklı platform bileşen aileleriyle kurmayı ele alır. **Platform Bileşen Aileleri** dersi, iki tasarım dilinin bileşen kümelerini ve bir eylem düğmesinin genişliğini sabit bir yuvanın nasıl koruduğunu ölçer.
