GitHub

Row Heights

Self-sizing rows that adapt to your content automatically.

By default, all rows have the same fixed height. But when your content varies — long descriptions, multi-line text, or custom cells with different layouts — you need rows that size themselves to fit.

Choosing a Height Mode

SwiftDataTables offers two height modes. Choose based on your content:

ModeBest ForPerformance
.fixed(CGFloat)Uniform content, single-line textFastest — no measurement needed
.automatic(estimated:)Variable content, text wrapping, custom cellsMeasures each row via Auto Layout

Fixed Height

The simplest option. Every row gets the same height, no questions asked.

var config = DataTableConfiguration()
config.rowHeightMode = .fixed(44)  // All rows are exactly 44 points tall

When to use: Your data fits in one line per cell, all cells have similar content, and you want maximum scroll performance.

If content is taller than the fixed height, it gets clipped. There's no truncation indicator — the cell just cuts off.

Automatic Height

Rows measure themselves based on their content. A row with three lines of text will be taller than a row with one line.

var config = DataTableConfiguration()
config.rowHeightMode = .automatic(estimated: 60)

The estimated parameter

Before a row scrolls into view, SwiftDataTables doesn't know how tall it is. The estimated value is used as a placeholder until the row is actually measured.

  • Too low — Scroll bar jumps as rows turn out taller than expected
  • Too high — Wasted space, scroll bar still jumps
  • Just right — Smooth scrolling, stable scroll bar

Set estimated to your average row height. If most rows are around 50-60 points, use estimated: 55.

How measurement works

  1. Initial layout — All rows use the estimated height. This lets the table calculate scroll bounds immediately.
  2. Lazy measurement — As a row scrolls into view, it's measured using Auto Layout (systemLayoutSizeFitting).
  3. Height caching — Once measured, the height is cached. Scrolling back to that row reuses the cached value.
  4. Scroll anchoring — When a row's measured height differs from the estimate, the scroll position adjusts to prevent jumping.

Combining with Text Wrapping

Automatic heights are essential when using text wrapping. Without them, wrapped text gets clipped.

var config = DataTableConfiguration()

// Enable text wrapping
config.textLayout = .wrap

// Let rows grow to fit wrapped text
config.rowHeightMode = .automatic(estimated: 60)

// Cap column width to force wrapping
config.maxColumnWidth = 250

Without maxColumnWidth, columns might be wide enough that text never wraps. The cap forces text onto multiple lines, which automatic height then accommodates.

Per-Row Height Overrides

Need specific rows to have custom heights? Use the delegate method:

func dataTable(_ dataTable: SwiftDataTable, heightForRowAt index: Int) -> CGFloat? {
    // Make header row taller
    if index == 0 {
        return 80
    }
    
    // Use default height for all other rows
    return nil
}

Returning nil tells the table to use the configured rowHeightMode. Returning a value overrides it for that specific row.

Live Height Updates

When cell content changes while the user is interacting (typing in a text field, expanding a section), you need to update the row height without disrupting the interaction.

// In your custom cell's text view delegate
func textViewDidChange(_ textView: UITextView) {
    // Update your data model
    notes[rowIndex].content = textView.text
    
    // Tell the table to remeasure this row
    // The cell stays on screen, keyboard stays up, no flicker
    dataTable.remeasureRow(rowIndex)
}

remeasureRow(_:) only works with .automatic height mode. With .fixed, the height can't change.

Performance with Large Datasets

With 100,000+ rows, measuring each row on-demand can cause micro-stutters during fast scrolling. The prefetchWindow parameter measures rows slightly ahead of the visible area:

config.rowHeightMode = .automatic(estimated: 44, prefetchWindow: 10)

This measures 10 rows above and below the visible area in advance. When you scroll, those rows are already measured, eliminating the stutter.

prefetchWindowEffect
0 (default)Only measure rows as they become visible
5-10Good balance for most apps
20+Very fast scrolling, but uses more memory for cached heights